mirror of
https://github.com/topjohnwu/Magisk
synced 2025-11-04 17:32:31 +01:00
Compare commits
141 Commits
manager-v5
...
manager-v5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5ceee547c | ||
|
|
b612bce779 | ||
|
|
2e88e5e9c7 | ||
|
|
9a7aa25c90 | ||
|
|
c4420fe932 | ||
|
|
a5260f3a95 | ||
|
|
47ccf4b1f5 | ||
|
|
a356b21895 | ||
|
|
614a36c888 | ||
|
|
f520fe36bd | ||
|
|
7273a1c34d | ||
|
|
dc45cbce37 | ||
|
|
708d8f75c0 | ||
|
|
bd37d90228 | ||
|
|
b1ad691464 | ||
|
|
f4e7baf31e | ||
|
|
c0e60c41f2 | ||
|
|
c8dad43e00 | ||
|
|
a8f124704d | ||
|
|
eed2816491 | ||
|
|
a6334b3e35 | ||
|
|
334beebfeb | ||
|
|
13dad848bd | ||
|
|
e518f4cef8 | ||
|
|
c8fd5da2da | ||
|
|
3a74729ecc | ||
|
|
49c672ac4d | ||
|
|
b570cb5b77 | ||
|
|
97bf388471 | ||
|
|
1a32aaea6f | ||
|
|
4635883dec | ||
|
|
3ba6db4a50 | ||
|
|
2f1de25747 | ||
|
|
f60fd42ac0 | ||
|
|
ecc8f9c792 | ||
|
|
e295dfdcf7 | ||
|
|
fc42c25390 | ||
|
|
27d5858e06 | ||
|
|
e1ef732b60 | ||
|
|
9840b95c21 | ||
|
|
a6f8446d81 | ||
|
|
c1c844c830 | ||
|
|
389299afd1 | ||
|
|
826543a291 | ||
|
|
4ac83cfded | ||
|
|
64c363ce53 | ||
|
|
cca4347bf9 | ||
|
|
3ae3d4926a | ||
|
|
36025d6d9f | ||
|
|
e171362e3e | ||
|
|
3e0bf2ae15 | ||
|
|
07aa9f4b8b | ||
|
|
b2d9f3fc64 | ||
|
|
5fb3e9167e | ||
|
|
99c74b31be | ||
|
|
ce5b13824e | ||
|
|
c39170c42e | ||
|
|
fd19fbf300 | ||
|
|
166469827f | ||
|
|
a34ed538b6 | ||
|
|
5f22d3e055 | ||
|
|
fdd700f3e5 | ||
|
|
adf930f126 | ||
|
|
05f41928cd | ||
|
|
2ee0829871 | ||
|
|
743560825d | ||
|
|
e3d84ac349 | ||
|
|
266c832b30 | ||
|
|
f5374a024e | ||
|
|
4956d826fb | ||
|
|
f5cc2af5d0 | ||
|
|
5880d4a6ec | ||
|
|
ae05dce958 | ||
|
|
9ebe372a9a | ||
|
|
e6e04cc5b3 | ||
|
|
12352510fd | ||
|
|
2b3d927937 | ||
|
|
a8890740f5 | ||
|
|
f60d7ee54b | ||
|
|
896ca2ef6b | ||
|
|
c036f6d529 | ||
|
|
6f457c0c59 | ||
|
|
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 |
@@ -1,15 +1,15 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 26
|
compileSdkVersion 27
|
||||||
buildToolsVersion "26.0.1"
|
buildToolsVersion "27.0.1"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.topjohnwu.magisk"
|
applicationId "com.topjohnwu.magisk"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 26
|
targetSdkVersion 27
|
||||||
versionCode 54
|
versionCode 64
|
||||||
versionName "5.3.0"
|
versionName "5.4.3"
|
||||||
ndk {
|
ndk {
|
||||||
moduleName 'zipadjust'
|
moduleName 'zipadjust'
|
||||||
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
||||||
@@ -45,24 +45,22 @@ android {
|
|||||||
disable 'MissingTranslation'
|
disable 'MissingTranslation'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
google()
|
||||||
maven { url "https://jitpack.io" }
|
maven { url "https://jitpack.io" }
|
||||||
maven { url "https://maven.google.com" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
implementation project(':resource')
|
implementation project(':crypto')
|
||||||
implementation 'com.android.support:recyclerview-v7:26.0.2'
|
implementation 'com.android.support:recyclerview-v7:27.0.1'
|
||||||
implementation 'com.android.support:cardview-v7:26.0.2'
|
implementation 'com.android.support:cardview-v7:27.0.1'
|
||||||
implementation 'com.android.support:design:26.0.2'
|
implementation 'com.android.support:design:27.0.1'
|
||||||
implementation 'com.android.support:support-v4:26.0.2'
|
implementation 'com.android.support:support-v4:27.0.1'
|
||||||
implementation 'com.jakewharton:butterknife:8.8.1'
|
implementation 'com.jakewharton:butterknife:8.8.1'
|
||||||
implementation 'com.atlassian.commonmark:commonmark:0.9.0'
|
implementation 'com.atlassian.commonmark:commonmark:0.10.0'
|
||||||
implementation 'org.bouncycastle:bcprov-jdk15on:1.57'
|
|
||||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.57'
|
|
||||||
implementation 'org.kamranzafar:jtar:2.3'
|
implementation 'org.kamranzafar:jtar:2.3'
|
||||||
implementation 'com.google.android.gms:play-services-safetynet:9.0.1'
|
|
||||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
|
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 *;
|
# public *;
|
||||||
#}
|
#}
|
||||||
|
|
||||||
|
# Keep all names, we are open source anyway :)
|
||||||
|
-keepnames class ** { *; }
|
||||||
|
|
||||||
# BouncyCastle
|
# BouncyCastle
|
||||||
-keep class org.bouncycastle.** { *; }
|
-keep class org.bouncycastle.jcajce.provider.** { *; }
|
||||||
-dontwarn javax.naming.**
|
-dontwarn javax.naming.**
|
||||||
|
|
||||||
-dontwarn android.content.**
|
|
||||||
-dontwarn android.animation.**
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,12 @@
|
|||||||
android:name=".MagiskManager"
|
android:name=".MagiskManager"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
|
android:directBootAware="true"
|
||||||
|
tools:ignore="UnusedAttribute">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
@@ -72,6 +74,7 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver android:name=".receivers.ManagerUpdate" />
|
<receiver android:name=".receivers.ManagerUpdate" />
|
||||||
|
<receiver android:name=".receivers.RebootReceiver" />
|
||||||
|
|
||||||
<service android:name=".services.OnBootIntentService" />
|
<service android:name=".services.OnBootIntentService" />
|
||||||
<service
|
<service
|
||||||
@@ -89,9 +92,10 @@
|
|||||||
android:resource="@xml/file_paths" />
|
android:resource="@xml/file_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<!-- Hardcode GMS version -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.gms.version"
|
android:name="com.google.android.gms.version"
|
||||||
android:value="@integer/google_play_services_version" />
|
android:value="11717000" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 57 KiB |
@@ -17,19 +17,17 @@ import android.widget.TextView;
|
|||||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class AboutActivity extends Activity {
|
public class AboutActivity extends Activity {
|
||||||
|
|
||||||
private static final String DONATION_URL = "https://www.paypal.me/topjohnwu";
|
|
||||||
private static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
|
|
||||||
private static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/MagiskManager";
|
|
||||||
|
|
||||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||||
@BindView(R.id.app_version_info) AboutCardRow appVersionInfo;
|
@BindView(R.id.app_version_info) AboutCardRow appVersionInfo;
|
||||||
@BindView(R.id.app_changelog) AboutCardRow appChangelog;
|
@BindView(R.id.app_changelog) AboutCardRow appChangelog;
|
||||||
@@ -57,7 +55,7 @@ public class AboutActivity extends Activity {
|
|||||||
ab.setDisplayHomeAsUpEnabled(true);
|
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;
|
String changes = null;
|
||||||
try (InputStream is = getAssets().open("changelog.html")) {
|
try (InputStream is = getAssets().open("changelog.html")) {
|
||||||
@@ -119,13 +117,13 @@ public class AboutActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
appSourceCode.removeSummary();
|
appSourceCode.removeSummary();
|
||||||
appSourceCode.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(SOURCE_CODE_URL))));
|
appSourceCode.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.SOURCE_CODE_URL))));
|
||||||
|
|
||||||
supportThread.removeSummary();
|
supportThread.removeSummary();
|
||||||
supportThread.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(XDA_THREAD))));
|
supportThread.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.XDA_THREAD))));
|
||||||
|
|
||||||
donation.removeSummary();
|
donation.removeSummary();
|
||||||
donation.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(DONATION_URL))));
|
donation.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.DONATION_URL))));
|
||||||
|
|
||||||
setFloating();
|
setFloating();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,22 +4,29 @@ import android.content.Intent;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.view.LayoutInflater;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ScrollView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.FlashZip;
|
import com.topjohnwu.magisk.asyncs.FlashZip;
|
||||||
import com.topjohnwu.magisk.asyncs.InstallMagisk;
|
import com.topjohnwu.magisk.asyncs.InstallMagisk;
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
import com.topjohnwu.magisk.utils.AdaptiveList;
|
import com.topjohnwu.magisk.container.CallbackList;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@@ -27,28 +34,45 @@ import butterknife.OnClick;
|
|||||||
|
|
||||||
public class FlashActivity extends Activity {
|
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.toolbar) Toolbar toolbar;
|
||||||
@BindView(R.id.flash_logs) RecyclerView flashLogs;
|
@BindView(R.id.txtLog) TextView flashLogs;
|
||||||
@BindView(R.id.button_panel) LinearLayout buttonPanel;
|
@BindView(R.id.button_panel) public LinearLayout buttonPanel;
|
||||||
@BindView(R.id.reboot) Button reboot;
|
@BindView(R.id.reboot) public Button reboot;
|
||||||
|
@BindView(R.id.scrollView) ScrollView sv;
|
||||||
|
|
||||||
|
private List<String> logs;
|
||||||
|
|
||||||
@OnClick(R.id.no_thanks)
|
@OnClick(R.id.no_thanks)
|
||||||
public void dismiss() {
|
void dismiss() {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.reboot)
|
@OnClick(R.id.reboot)
|
||||||
public void reboot() {
|
void reboot() {
|
||||||
getShell().su_raw("reboot");
|
Shell.su_raw("/system/bin/reboot");
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.save_logs)
|
||||||
|
void saveLogs() {
|
||||||
|
Calendar now = Calendar.getInstance();
|
||||||
|
String filename = String.format(Locale.US,
|
||||||
|
"install_log_%04d%02d%02d_%02d:%02d:%02d.log",
|
||||||
|
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||||
|
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||||
|
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
||||||
|
|
||||||
|
File logFile = new File(Const.EXTERNAL_PATH + "/logs", filename);
|
||||||
|
logFile.getParentFile().mkdirs();
|
||||||
|
try (FileWriter writer = new FileWriter(logFile)) {
|
||||||
|
for (String s : logs) {
|
||||||
|
writer.write(s);
|
||||||
|
writer.write('\n');
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MagiskManager.toast(logFile.getPath(), Toast.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -56,55 +80,45 @@ public class FlashActivity extends Activity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_flash);
|
setContentView(R.layout.activity_flash);
|
||||||
ButterKnife.bind(this);
|
ButterKnife.bind(this);
|
||||||
AdaptiveList<String> rootShellOutput = new AdaptiveList<>(flashLogs);
|
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
ActionBar ab = getSupportActionBar();
|
ActionBar ab = getSupportActionBar();
|
||||||
if (ab != null) {
|
if (ab != null) {
|
||||||
ab.setTitle(R.string.flashing);
|
ab.setTitle(R.string.flashing);
|
||||||
}
|
}
|
||||||
setFloating();
|
setFloating();
|
||||||
|
setFinishOnTouchOutside(false);
|
||||||
if (!Shell.rootAccess())
|
if (!Shell.rootAccess())
|
||||||
reboot.setVisibility(View.GONE);
|
reboot.setVisibility(View.GONE);
|
||||||
|
|
||||||
flashLogs.setAdapter(new FlashLogAdapter(rootShellOutput));
|
logs = new ArrayList<>();
|
||||||
|
List<String> console = new CallbackList<String>() {
|
||||||
|
@Override
|
||||||
|
public synchronized void onAddElement(String e) {
|
||||||
|
logs.add(e);
|
||||||
|
flashLogs.setText(TextUtils.join("\n", this));
|
||||||
|
sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// We must receive a Uri of the target zip
|
// We must receive a Uri of the target zip
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
Uri uri = intent.getData();
|
Uri uri = intent.getData();
|
||||||
|
|
||||||
boolean keepEnc = intent.getBooleanExtra(SET_ENC, false);
|
boolean keepEnc = intent.getBooleanExtra(Const.Key.FLASH_SET_ENC, false);
|
||||||
boolean keepVerity = intent.getBooleanExtra(SET_VERITY, false);
|
boolean keepVerity = intent.getBooleanExtra(Const.Key.FLASH_SET_VERITY, false);
|
||||||
|
|
||||||
switch (getIntent().getStringExtra(SET_ACTION)) {
|
switch (intent.getStringExtra(Const.Key.FLASH_ACTION)) {
|
||||||
case FLASH_ZIP:
|
case Const.Value.FLASH_ZIP:
|
||||||
new FlashZip(this, uri, rootShellOutput)
|
new FlashZip(this, uri, console, logs).exec();
|
||||||
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
|
break;
|
||||||
|
case Const.Value.PATCH_BOOT:
|
||||||
|
new InstallMagisk(this, console, logs, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT))
|
||||||
.exec();
|
.exec();
|
||||||
break;
|
break;
|
||||||
case PATCH_BOOT:
|
case Const.Value.FLASH_MAGISK:
|
||||||
new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(SET_BOOT))
|
new InstallMagisk(this, console, logs, uri, keepEnc, keepVerity, intent.getStringExtra(Const.Key.FLASH_SET_BOOT))
|
||||||
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
|
|
||||||
.exec();
|
.exec();
|
||||||
break;
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,40 +126,4 @@ public class FlashActivity extends Activity {
|
|||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
// Prevent user accidentally press back button
|
// Prevent user accidentally press back button
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
|
||||||
.inflate(R.layout.list_item_flashlog, parent, false);
|
|
||||||
return new ViewHolder(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
|
||||||
holder.text.setText(mList.get(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return mList.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
|
|
||||||
@BindView(R.id.textView) TextView text;
|
|
||||||
|
|
||||||
public ViewHolder(View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
ButterKnife.bind(this, itemView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,13 +33,10 @@ public class LogFragment extends Fragment {
|
|||||||
|
|
||||||
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
|
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
|
||||||
|
|
||||||
if (getApplication().isSuClient) {
|
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
|
||||||
adapter.addTab(new SuLogFragment(), getString(R.string.superuser));
|
|
||||||
tab.setupWithViewPager(viewPager);
|
|
||||||
tab.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
||||||
|
tab.setupWithViewPager(viewPager);
|
||||||
|
tab.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
viewPager.setAdapter(adapter);
|
viewPager.setAdapter(adapter);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -84,7 +84,7 @@ public class MagiskHideFragment extends Fragment implements Topic.Subscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
appAdapter.filter(lastFilter);
|
appAdapter.filter(lastFilter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -22,6 +20,7 @@ import android.widget.Toast;
|
|||||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
@@ -29,6 +28,7 @@ import java.io.File;
|
|||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@@ -36,8 +36,6 @@ import butterknife.Unbinder;
|
|||||||
|
|
||||||
public class MagiskLogFragment extends Fragment {
|
public class MagiskLogFragment extends Fragment {
|
||||||
|
|
||||||
private static final String MAGISK_LOG = "/cache/magisk.log";
|
|
||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
|
|
||||||
@BindView(R.id.txtLog) TextView txtLog;
|
@BindView(R.id.txtLog) TextView txtLog;
|
||||||
@@ -110,30 +108,29 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
super(MagiskLogFragment.this.getActivity());
|
super(MagiskLogFragment.this.getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
|
||||||
@Override
|
@Override
|
||||||
protected Object doInBackground(Object... params) {
|
protected Object doInBackground(Object... params) {
|
||||||
mode = (int) params[0];
|
mode = (int) params[0];
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 0:
|
case 0:
|
||||||
StringBuildingList logList = new StringBuildingList();
|
StringBuildingList logList = new StringBuildingList();
|
||||||
getShell().su(logList, "cat " + MAGISK_LOG);
|
Shell.su(logList, "cat " + Const.MAGISK_LOG + " | tail -n 1000");
|
||||||
return logList.toString();
|
return logList.getCharSequence();
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
getShell().su_raw("echo -n > " + MAGISK_LOG);
|
Shell.su_raw("echo -n > " + Const.MAGISK_LOG);
|
||||||
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
Calendar now = Calendar.getInstance();
|
Calendar now = Calendar.getInstance();
|
||||||
String filename = String.format(
|
String filename = String.format(Locale.US,
|
||||||
"magisk_%s_%04d%02d%02d_%02d%02d%02d.log", "error",
|
"magisk_log_%04d%02d%02d_%02d:%02d:%02d.log",
|
||||||
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||||
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
||||||
|
|
||||||
targetFile = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/" + filename);
|
targetFile = new File(Const.EXTERNAL_PATH + "/logs", filename);
|
||||||
|
|
||||||
if ((!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs())
|
if ((!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs())
|
||||||
|| (targetFile.exists() && !targetFile.delete())) {
|
|| (targetFile.exists() && !targetFile.delete())) {
|
||||||
@@ -142,7 +139,7 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
|
|
||||||
try (FileWriter out = new FileWriter(targetFile)) {
|
try (FileWriter out = new FileWriter(targetFile)) {
|
||||||
FileWritingList fileWritingList = new FileWritingList(out);
|
FileWritingList fileWritingList = new FileWritingList(out);
|
||||||
getShell().su(fileWritingList, "cat " + MAGISK_LOG);
|
Shell.su(fileWritingList, "cat " + Const.MAGISK_LOG);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
@@ -158,21 +155,21 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
String llog = (String) o;
|
CharSequence llog = (CharSequence) o;
|
||||||
progressBar.setVisibility(View.GONE);
|
progressBar.setVisibility(View.GONE);
|
||||||
if (TextUtils.isEmpty(llog))
|
if (TextUtils.isEmpty(llog))
|
||||||
txtLog.setText(R.string.log_is_empty);
|
txtLog.setText(R.string.log_is_empty);
|
||||||
else
|
else
|
||||||
txtLog.setText(llog);
|
txtLog.setText(llog);
|
||||||
svLog.post(() -> svLog.scrollTo(0, txtLog.getHeight()));
|
svLog.postDelayed(() -> svLog.fullScroll(ScrollView.FOCUS_DOWN), 100);
|
||||||
hsvLog.post(() -> hsvLog.scrollTo(0, 0));
|
hsvLog.postDelayed(() -> hsvLog.fullScroll(ScrollView.FOCUS_LEFT), 100);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
boolean bool = (boolean) o;
|
boolean bool = (boolean) o;
|
||||||
if (bool) {
|
if (bool) {
|
||||||
getMagiskManager().toast(targetFile.toString(), Toast.LENGTH_LONG);
|
MagiskManager.toast(targetFile.getPath(), Toast.LENGTH_LONG);
|
||||||
} else {
|
} else {
|
||||||
getMagiskManager().toast(R.string.logs_save_failed, Toast.LENGTH_LONG);
|
MagiskManager.toast(R.string.logs_save_failed, Toast.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -205,9 +202,8 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public CharSequence getCharSequence() {
|
||||||
public String toString() {
|
return builder;
|
||||||
return builder.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ import android.os.Bundle;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.NavigationView;
|
import android.support.design.widget.NavigationView;
|
||||||
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
import android.support.v4.widget.DrawerLayout;
|
import android.support.v4.widget.DrawerLayout;
|
||||||
@@ -16,6 +17,7 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
@@ -38,11 +40,27 @@ public class MainActivity extends Activity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
getMagiskManager().startup();
|
|
||||||
|
|
||||||
prefs = getMagiskManager().prefs;
|
MagiskManager mm = getMagiskManager();
|
||||||
|
|
||||||
if (getMagiskManager().isDarkTheme) {
|
if (!mm.hasInit) {
|
||||||
|
Intent intent = new Intent(this, SplashActivity.class);
|
||||||
|
String section = getIntent().getStringExtra(Const.Key.OPEN_SECTION);
|
||||||
|
if (section != null) {
|
||||||
|
intent.putExtra(Const.Key.OPEN_SECTION, section);
|
||||||
|
}
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
String perm = getIntent().getStringExtra(Const.Key.INTENT_PERM);
|
||||||
|
if (perm != null) {
|
||||||
|
ActivityCompat.requestPermissions(this, new String[] { perm }, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
prefs = mm.prefs;
|
||||||
|
|
||||||
|
if (mm.isDarkTheme) {
|
||||||
setTheme(R.style.AppTheme_Dark);
|
setTheme(R.style.AppTheme_Dark);
|
||||||
}
|
}
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -70,10 +88,9 @@ public class MainActivity extends Activity
|
|||||||
toggle.syncState();
|
toggle.syncState();
|
||||||
|
|
||||||
if (savedInstanceState == null)
|
if (savedInstanceState == null)
|
||||||
navigate(getIntent().getStringExtra(MagiskManager.INTENT_SECTION));
|
navigate(getIntent().getStringExtra(Const.Key.OPEN_SECTION));
|
||||||
|
|
||||||
navigationView.setNavigationItemSelectedListener(this);
|
navigationView.setNavigationItemSelectedListener(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -102,7 +119,7 @@ public class MainActivity extends Activity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
recreate();
|
recreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,17 +129,18 @@ public class MainActivity extends Activity
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void checkHideSection() {
|
public void checkHideSection() {
|
||||||
|
MagiskManager mm = getMagiskManager();
|
||||||
Menu menu = navigationView.getMenu();
|
Menu menu = navigationView.getMenu();
|
||||||
menu.findItem(R.id.magiskhide).setVisible(
|
menu.findItem(R.id.magiskhide).setVisible(
|
||||||
Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 1300
|
Shell.rootAccess() && mm.magiskVersionCode >= 1300
|
||||||
&& prefs.getBoolean("magiskhide", false));
|
&& prefs.getBoolean(Const.Key.MAGISKHIDE, false));
|
||||||
menu.findItem(R.id.modules).setVisible(
|
menu.findItem(R.id.modules).setVisible(
|
||||||
Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 0);
|
Shell.rootAccess() && mm.magiskVersionCode >= 0);
|
||||||
menu.findItem(R.id.downloads).setVisible(Utils.checkNetworkStatus(this) &&
|
menu.findItem(R.id.downloads).setVisible(Utils.checkNetworkStatus() &&
|
||||||
Shell.rootAccess() && getMagiskManager().magiskVersionCode >= 0);
|
Shell.rootAccess() && mm.magiskVersionCode >= 0);
|
||||||
|
menu.setGroupVisible(R.id.second_group, !mm.coreOnly);
|
||||||
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
|
menu.findItem(R.id.log).setVisible(Shell.rootAccess());
|
||||||
menu.findItem(R.id.superuser).setVisible(
|
menu.findItem(R.id.superuser).setVisible(Shell.rootAccess());
|
||||||
Shell.rootAccess() && getMagiskManager().isSuClient);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void navigate(String item) {
|
public void navigate(String item) {
|
||||||
@@ -176,7 +194,7 @@ public class MainActivity extends Activity
|
|||||||
displayFragment(new ReposFragment(), "downloads", true);
|
displayFragment(new ReposFragment(), "downloads", true);
|
||||||
break;
|
break;
|
||||||
case R.id.magiskhide:
|
case R.id.magiskhide:
|
||||||
displayFragment(new MagiskHideFragment(), "magiskhide", true);
|
displayFragment(new MagiskHideFragment(), Const.Key.MAGISKHIDE, true);
|
||||||
break;
|
break;
|
||||||
case R.id.log:
|
case R.id.log:
|
||||||
displayFragment(new LogFragment(), "log", false);
|
displayFragment(new LogFragment(), "log", false);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -14,9 +15,10 @@ import android.widget.TextView;
|
|||||||
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
||||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -28,17 +30,17 @@ import butterknife.Unbinder;
|
|||||||
|
|
||||||
public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
||||||
|
|
||||||
private static final int FETCH_ZIP_CODE = 2;
|
|
||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
@BindView(R.id.empty_rv) TextView emptyRv;
|
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||||
@OnClick(R.id.fab)
|
@OnClick(R.id.fab)
|
||||||
public void selectFile() {
|
public void selectFile() {
|
||||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, () -> {
|
||||||
intent.setType("application/zip");
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
startActivityForResult(intent, FETCH_ZIP_CODE);
|
intent.setType("application/zip");
|
||||||
|
startActivityForResult(intent, Const.ID.FETCH_ZIP);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Module> listModules = new ArrayList<>();
|
private List<Module> listModules = new ArrayList<>();
|
||||||
@@ -51,7 +53,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
|||||||
|
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
new LoadModules(getActivity()).exec();
|
new LoadModules().exec();
|
||||||
});
|
});
|
||||||
|
|
||||||
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
@@ -72,8 +74,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
Logger.dev("ModulesFragment: UI refresh triggered");
|
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,10 +85,10 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (requestCode == FETCH_ZIP_CODE && 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(), FlashActivity.class);
|
Intent intent = new Intent(getActivity(), FlashActivity.class);
|
||||||
intent.setData(data.getData()).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP);
|
intent.setData(data.getData()).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import android.widget.TextView;
|
|||||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
|
|
||||||
import butterknife.BindView;
|
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.empty_rv) TextView emptyRv;
|
||||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||||
|
|
||||||
private ReposAdapter adapter;
|
public static ReposAdapter adapter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
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);
|
View view = inflater.inflate(R.layout.fragment_repos, container, false);
|
||||||
unbinder = ButterKnife.bind(this, view);
|
unbinder = ButterKnife.bind(this, view);
|
||||||
|
|
||||||
adapter = new ReposAdapter(getApplication().repoDB, getApplication().moduleMap);
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
|
|
||||||
mSwipeRefreshLayout.setRefreshing(true);
|
mSwipeRefreshLayout.setRefreshing(true);
|
||||||
|
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
new UpdateRepos(getActivity()).exec();
|
emptyRv.setVisibility(View.GONE);
|
||||||
|
new UpdateRepos(true).exec();
|
||||||
});
|
});
|
||||||
|
|
||||||
getActivity().setTitle(R.string.downloads);
|
getActivity().setTitle(R.string.downloads);
|
||||||
@@ -59,10 +56,21 @@ public class ReposFragment extends Fragment implements Topic.Subscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onResume() {
|
||||||
Logger.dev("ReposFragment: UI refresh triggered");
|
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);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
adapter.notifyDBChanged();
|
|
||||||
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
||||||
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,27 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.job.JobInfo;
|
||||||
|
import android.app.job.JobScheduler;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
|
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||||
|
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||||
|
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
|
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class SplashActivity extends Activity {
|
public class SplashActivity extends Activity {
|
||||||
|
|
||||||
@@ -11,14 +29,106 @@ public class SplashActivity extends Activity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
getMagiskManager().startup();
|
MagiskManager mm = getMagiskManager();
|
||||||
|
|
||||||
|
// Dynamic detect all locales
|
||||||
|
new LoadLocale().exec();
|
||||||
|
|
||||||
|
// Create notification channel on Android O
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
NotificationChannel channel = new NotificationChannel(Const.ID.NOTIFICATION_CHANNEL,
|
||||||
|
getString(R.string.magisk_updates), NotificationManager.IMPORTANCE_DEFAULT);
|
||||||
|
getSystemService(NotificationManager.class).createNotificationChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
mm.loadMagiskInfo();
|
||||||
|
LoadModules loadModuleTask = new LoadModules();
|
||||||
|
|
||||||
|
if (Utils.checkNetworkStatus()) {
|
||||||
|
|
||||||
|
// Fire update check
|
||||||
|
new CheckUpdates().exec();
|
||||||
|
|
||||||
|
// Add repo update check
|
||||||
|
loadModuleTask.setCallBack(() -> new UpdateRepos(false).exec());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Magisk working as expected
|
||||||
|
if (Shell.rootAccess() && mm.magiskVersionCode > 0) {
|
||||||
|
|
||||||
|
List<String> ret = Shell.su("echo \"$BOOTIMAGE\"");
|
||||||
|
if (Utils.isValidShellResponse(ret)) {
|
||||||
|
mm.bootBlock = ret.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup suDB
|
||||||
|
SuDatabaseHelper.setupSuDB();
|
||||||
|
|
||||||
|
// Check alternative Magisk Manager
|
||||||
|
String pkg;
|
||||||
|
if (getPackageName().equals(Const.ORIG_PKG_NAME) &&
|
||||||
|
(pkg = mm.suDB.getStrings(Const.Key.SU_REQUESTER, null)) != null) {
|
||||||
|
Shell.su_raw("pm uninstall " + pkg);
|
||||||
|
mm.suDB.setStrings(Const.Key.SU_REQUESTER, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add update checking service
|
||||||
|
if (Const.Value.UPDATE_SERVICE_VER > mm.updateServiceVersion) {
|
||||||
|
ComponentName service = new ComponentName(this, 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();
|
||||||
|
((JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(info);
|
||||||
|
mm.updateServiceVersion = Const.Value.UPDATE_SERVICE_VER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire asynctasks
|
||||||
|
loadModuleTask.exec();
|
||||||
|
|
||||||
|
// Check dtbo status
|
||||||
|
Utils.patchDTBO();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write back default values
|
||||||
|
mm.prefs.edit()
|
||||||
|
.putBoolean(Const.Key.DARK_THEME, mm.isDarkTheme)
|
||||||
|
.putBoolean(Const.Key.MAGISKHIDE, mm.magiskHide)
|
||||||
|
.putBoolean(Const.Key.UPDATE_NOTIFICATION, mm.updateNotification)
|
||||||
|
.putBoolean(Const.Key.HOSTS, Utils.itemExist(Const.MAGISK_HOST_FILE()))
|
||||||
|
.putBoolean(Const.Key.DISABLE, Utils.itemExist(Const.MAGISK_DISABLE_FILE))
|
||||||
|
.putBoolean(Const.Key.SU_REAUTH, mm.suReauth)
|
||||||
|
.putString(Const.Key.SU_REQUEST_TIMEOUT, String.valueOf(mm.suRequestTimeout))
|
||||||
|
.putString(Const.Key.SU_AUTO_RESPONSE, String.valueOf(mm.suResponseType))
|
||||||
|
.putString(Const.Key.SU_NOTIFICATION, String.valueOf(mm.suNotificationType))
|
||||||
|
.putString(Const.Key.ROOT_ACCESS, String.valueOf(mm.suAccessState))
|
||||||
|
.putString(Const.Key.SU_MULTIUSER_MODE, String.valueOf(mm.multiuserMode))
|
||||||
|
.putString(Const.Key.SU_MNT_NS, String.valueOf(mm.suNamespaceMode))
|
||||||
|
.putString(Const.Key.UPDATE_CHANNEL, String.valueOf(mm.updateChannel))
|
||||||
|
.putString(Const.Key.LOCALE, mm.localeConfig)
|
||||||
|
.putString(Const.Key.BOOT_FORMAT, mm.bootFormat)
|
||||||
|
.putInt(Const.Key.UPDATE_SERVICE_VER, mm.updateServiceVersion)
|
||||||
|
.apply();
|
||||||
|
|
||||||
|
mm.hasInit = true;
|
||||||
|
|
||||||
Intent intent = new Intent(this, MainActivity.class);
|
Intent intent = new Intent(this, MainActivity.class);
|
||||||
String section = getIntent().getStringExtra(MagiskManager.INTENT_SECTION);
|
intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION));
|
||||||
if (section != null) {
|
intent.putExtra(Const.Key.INTENT_PERM, getIntent().getStringExtra(Const.Key.INTENT_PERM));
|
||||||
intent.putExtra(MagiskManager.INTENT_SECTION, section);
|
|
||||||
}
|
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class LoadLocale extends ParallelTask<Void, Void, Void> {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... voids) {
|
||||||
|
MagiskManager.get().locales = Utils.getAvailableLocale();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void aVoid) {
|
||||||
|
MagiskManager.get().localeDone.publish();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
import com.topjohnwu.magisk.container.Policy;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -16,12 +17,12 @@ import android.widget.TextView;
|
|||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -31,23 +32,11 @@ import butterknife.ButterKnife;
|
|||||||
|
|
||||||
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
|
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
|
||||||
|
|
||||||
public static final List<String> BLACKLIST = Arrays.asList(
|
|
||||||
"android",
|
|
||||||
"com.topjohnwu.magisk",
|
|
||||||
"com.google.android.gms"
|
|
||||||
);
|
|
||||||
|
|
||||||
private static final List<String> SNLIST = Arrays.asList(
|
|
||||||
"com.google.android.apps.walletnfcrel",
|
|
||||||
"com.nianticlabs.pokemongo"
|
|
||||||
);
|
|
||||||
|
|
||||||
private List<ApplicationInfo> mOriginalList, mList;
|
private List<ApplicationInfo> mOriginalList, mList;
|
||||||
private List<String> mHideList;
|
private List<String> mHideList;
|
||||||
private PackageManager pm;
|
private PackageManager pm;
|
||||||
private ApplicationFilter filter;
|
private ApplicationFilter filter;
|
||||||
private Topic magiskHideDone;
|
private Topic magiskHideDone;
|
||||||
private Shell shell;
|
|
||||||
|
|
||||||
public ApplicationAdapter(Context context) {
|
public ApplicationAdapter(Context context) {
|
||||||
mOriginalList = mList = Collections.emptyList();
|
mOriginalList = mList = Collections.emptyList();
|
||||||
@@ -55,10 +44,13 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
filter = new ApplicationFilter();
|
filter = new ApplicationFilter();
|
||||||
pm = context.getPackageManager();
|
pm = context.getPackageManager();
|
||||||
magiskHideDone = Utils.getMagiskManager(context).magiskHideDone;
|
magiskHideDone = Utils.getMagiskManager(context).magiskHideDone;
|
||||||
shell = Shell.getShell(context);
|
|
||||||
new LoadApps().exec();
|
new LoadApps().exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean lowercaseContains(CharSequence string, CharSequence nonNullLowercaseSearch) {
|
||||||
|
return !TextUtils.isEmpty(string) && string.toString().toLowerCase().contains(nonNullLowercaseSearch);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_app, parent, false);
|
View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_app, parent, false);
|
||||||
@@ -77,7 +69,7 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
holder.itemView.setOnClickListener(null);
|
holder.itemView.setOnClickListener(null);
|
||||||
holder.checkBox.setOnCheckedChangeListener(null);
|
holder.checkBox.setOnCheckedChangeListener(null);
|
||||||
|
|
||||||
if (SNLIST.contains(info.packageName)) {
|
if (Const.SN_DEFAULTLIST.contains(info.packageName)) {
|
||||||
holder.checkBox.setChecked(true);
|
holder.checkBox.setChecked(true);
|
||||||
holder.checkBox.setEnabled(false);
|
holder.checkBox.setEnabled(false);
|
||||||
holder.itemView.setOnClickListener(v ->
|
holder.itemView.setOnClickListener(v ->
|
||||||
@@ -89,10 +81,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
||||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
Utils.addMagiskHide(shell, info.packageName);
|
Shell.su_raw("magiskhide --add " + info.packageName);
|
||||||
mHideList.add(info.packageName);
|
mHideList.add(info.packageName);
|
||||||
} else {
|
} else {
|
||||||
Utils.rmMagiskHide(shell, info.packageName);
|
Shell.su_raw("magiskhide --rm " + info.packageName);
|
||||||
mHideList.remove(info.packageName);
|
mHideList.remove(info.packageName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -135,8 +127,8 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
mList = new ArrayList<>();
|
mList = new ArrayList<>();
|
||||||
String filter = constraint.toString().toLowerCase();
|
String filter = constraint.toString().toLowerCase();
|
||||||
for (ApplicationInfo info : mOriginalList) {
|
for (ApplicationInfo info : mOriginalList) {
|
||||||
if (Utils.lowercaseContains(info.loadLabel(pm), filter)
|
if (lowercaseContains(info.loadLabel(pm), filter)
|
||||||
|| Utils.lowercaseContains(info.packageName, filter)) {
|
|| lowercaseContains(info.packageName, filter)) {
|
||||||
mList.add(info);
|
mList.add(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,13 +149,13 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
mOriginalList = pm.getInstalledApplications(0);
|
mOriginalList = pm.getInstalledApplications(0);
|
||||||
for (Iterator<ApplicationInfo> i = mOriginalList.iterator(); i.hasNext(); ) {
|
for (Iterator<ApplicationInfo> i = mOriginalList.iterator(); i.hasNext(); ) {
|
||||||
ApplicationInfo info = i.next();
|
ApplicationInfo info = i.next();
|
||||||
if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) {
|
if (Const.SN_BLACKLIST.contains(info.packageName) || !info.enabled) {
|
||||||
i.remove();
|
i.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(mOriginalList, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
|
Collections.sort(mOriginalList, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
|
||||||
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
|
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
|
||||||
mHideList = Utils.listMagiskHide(shell);
|
mHideList = Shell.su("magiskhide --ls");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
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.module.Module;
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -38,7 +38,6 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||||
Context context = holder.itemView.getContext();
|
Context context = holder.itemView.getContext();
|
||||||
Shell rootShell = Shell.getShell(context);
|
|
||||||
final Module module = mList.get(position);
|
final Module module = mList.get(position);
|
||||||
|
|
||||||
String version = module.getVersion();
|
String version = module.getVersion();
|
||||||
@@ -56,10 +55,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
|||||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
int snack;
|
int snack;
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
module.removeDisableFile(rootShell);
|
module.removeDisableFile();
|
||||||
snack = R.string.disable_file_removed;
|
snack = R.string.disable_file_removed;
|
||||||
} else {
|
} else {
|
||||||
module.createDisableFile(rootShell);
|
module.createDisableFile();
|
||||||
snack = R.string.disable_file_created;
|
snack = R.string.disable_file_created;
|
||||||
}
|
}
|
||||||
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||||
@@ -69,10 +68,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
|||||||
boolean removed = module.willBeRemoved();
|
boolean removed = module.willBeRemoved();
|
||||||
int snack;
|
int snack;
|
||||||
if (removed) {
|
if (removed) {
|
||||||
module.deleteRemoveFile(rootShell);
|
module.deleteRemoveFile();
|
||||||
snack = R.string.remove_file_deleted;
|
snack = R.string.remove_file_deleted;
|
||||||
} else {
|
} else {
|
||||||
module.createRemoveFile(rootShell);
|
module.createRemoveFile();
|
||||||
snack = R.string.remove_file_created;
|
snack = R.string.remove_file_created;
|
||||||
}
|
}
|
||||||
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import com.topjohnwu.magisk.R;
|
|||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
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.SuDatabaseHelper;
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import com.topjohnwu.magisk.R;
|
|||||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
||||||
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
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.database.RepoDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
|
||||||
import com.topjohnwu.magisk.module.Repo;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -44,6 +44,7 @@ public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, R
|
|||||||
repoDB = db;
|
repoDB = db;
|
||||||
moduleMap = map;
|
moduleMap = map;
|
||||||
repoPairs = new ArrayList<>();
|
repoPairs = new ArrayList<>();
|
||||||
|
notifyDBChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
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.SuDatabaseHelper;
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
import com.topjohnwu.magisk.utils.WebService;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
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> {
|
||||||
|
|
||||||
|
private File dexPath;
|
||||||
|
private DexClassLoader loader;
|
||||||
|
|
||||||
|
public CheckSafetyNet(Activity activity) {
|
||||||
|
super(activity);
|
||||||
|
dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
MagiskManager mm = MagiskManager.get();
|
||||||
|
if (mm.snet_version != Const.Value.SNET_VER) {
|
||||||
|
Shell.sh("rm -rf " + dexPath.getParent());
|
||||||
|
}
|
||||||
|
mm.snet_version = Const.Value.SNET_VER;
|
||||||
|
mm.prefs.edit().putInt(Const.Key.SNET_VER, Const.Value.SNET_VER).apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Exception doInBackground(Void... voids) {
|
||||||
|
try {
|
||||||
|
if (!dexPath.exists()) {
|
||||||
|
HttpURLConnection conn = WebService.request(Const.Url.SNET_URL, null);
|
||||||
|
dexPath.getParentFile().mkdir();
|
||||||
|
try (
|
||||||
|
OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath));
|
||||||
|
InputStream in = new BufferedInputStream(conn.getInputStream())) {
|
||||||
|
Utils.inToOut(in, out);
|
||||||
|
}
|
||||||
|
conn.disconnect();
|
||||||
|
}
|
||||||
|
loader = new DexClassLoader(dexPath.toString(), dexPath.getParent(),
|
||||||
|
null, ClassLoader.getSystemClassLoader());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Exception err) {
|
||||||
|
MagiskManager mm = MagiskManager.get();
|
||||||
|
try {
|
||||||
|
if (err != null) throw err;
|
||||||
|
Class<?> helperClazz = loader.loadClass(Const.SNET_PKG + ".SafetyNetHelper");
|
||||||
|
Class<?> callbackClazz = loader.loadClass(Const.SNET_PKG + ".SafetyNetCallback");
|
||||||
|
Object helper = helperClazz.getConstructors()[0].newInstance(
|
||||||
|
getActivity(), dexPath.getPath(), Proxy.newProxyInstance(
|
||||||
|
loader, new Class[] { callbackClazz }, (proxy, method, args) -> {
|
||||||
|
mm.safetyNetDone.publish(false, args[0]);
|
||||||
|
return null;
|
||||||
|
}));
|
||||||
|
helperClazz.getMethod("attest").invoke(helper);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
mm.safetyNetDone.publish(false, -1);
|
||||||
|
}
|
||||||
|
super.onPostExecute(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.BuildConfig;
|
import com.topjohnwu.magisk.BuildConfig;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
|
import com.topjohnwu.magisk.utils.ShowUI;
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
import com.topjohnwu.magisk.utils.WebService;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@@ -12,37 +11,30 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||||
|
|
||||||
public static final int STABLE_CHANNEL = 0;
|
private boolean showNotification;
|
||||||
public static final int BETA_CHANNEL = 1;
|
|
||||||
|
|
||||||
private static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/stable.json";
|
public CheckUpdates() {
|
||||||
private static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/beta.json";
|
this(false);
|
||||||
|
|
||||||
private boolean showNotification = false;
|
|
||||||
|
|
||||||
public CheckUpdates(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckUpdates(Context context, boolean b) {
|
public CheckUpdates(boolean b) {
|
||||||
super(context);
|
|
||||||
showNotification = b;
|
showNotification = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
MagiskManager mm = getMagiskManager();
|
MagiskManager mm = MagiskManager.get();
|
||||||
if (mm == null) return null;
|
String jsonStr = "";
|
||||||
String jsonStr;
|
|
||||||
switch (mm.updateChannel) {
|
switch (mm.updateChannel) {
|
||||||
case STABLE_CHANNEL:
|
case Const.Value.STABLE_CHANNEL:
|
||||||
jsonStr = WebService.getString(STABLE_URL);
|
jsonStr = WebService.getString(Const.Url.STABLE_URL);
|
||||||
break;
|
break;
|
||||||
case BETA_CHANNEL:
|
case Const.Value.BETA_CHANNEL:
|
||||||
jsonStr = WebService.getString(BETA_URL);
|
jsonStr = WebService.getString(Const.Url.BETA_URL);
|
||||||
|
break;
|
||||||
|
case Const.Value.CUSTOM_CHANNEL:
|
||||||
|
jsonStr = WebService.getString(mm.customChannelUrl);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
jsonStr = null;
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
JSONObject json = new JSONObject(jsonStr);
|
JSONObject json = new JSONObject(jsonStr);
|
||||||
@@ -61,13 +53,12 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void v) {
|
protected void onPostExecute(Void v) {
|
||||||
MagiskManager mm = getMagiskManager();
|
MagiskManager mm = MagiskManager.get();
|
||||||
if (mm == null) return;
|
|
||||||
if (showNotification && mm.updateNotification) {
|
if (showNotification && mm.updateNotification) {
|
||||||
if (BuildConfig.VERSION_CODE < mm.remoteManagerVersionCode) {
|
if (BuildConfig.VERSION_CODE < mm.remoteManagerVersionCode) {
|
||||||
Utils.showManagerUpdateNotification(mm);
|
ShowUI.managerUpdateNotification();
|
||||||
} else if (mm.magiskVersionCode < mm.remoteMagiskVersionCode) {
|
} else if (mm.magiskVersionCode < mm.remoteMagiskVersionCode) {
|
||||||
Utils.showMagiskUpdateNotification(mm);
|
ShowUI.magiskUpdateNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mm.updateCheckDone.publish();
|
mm.updateCheckDone.publish();
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
public DownloadBusybox(Context context) {
|
|
||||||
super(context);
|
|
||||||
busybox = new File(context.getCacheDir(), "busybox");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... voids) {
|
|
||||||
Context context = getMagiskManager();
|
|
||||||
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();
|
|
||||||
BufferedInputStream bis = new BufferedInputStream(in);
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
int len;
|
|
||||||
while ((len = bis.read(buffer)) != -1) {
|
|
||||||
out.write(buffer, 0, len);
|
|
||||||
}
|
|
||||||
out.close();
|
|
||||||
bis.close();
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
if (busybox.exists()) {
|
|
||||||
getShell().su_raw(
|
|
||||||
"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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,13 +3,17 @@ package com.topjohnwu.magisk.asyncs;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.FlashActivity;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.AdaptiveList;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@@ -21,101 +25,84 @@ import java.util.List;
|
|||||||
public class FlashZip extends ParallelTask<Void, Void, Integer> {
|
public class FlashZip extends ParallelTask<Void, Void, Integer> {
|
||||||
|
|
||||||
private Uri mUri;
|
private Uri mUri;
|
||||||
private File mCachedFile, mScriptFile, mCheckFile;
|
private File mCachedFile;
|
||||||
|
private List<String> console, logs;
|
||||||
|
|
||||||
private String mFilename;
|
public FlashZip(Activity context, Uri uri, List<String> console, List<String> logs) {
|
||||||
private AdaptiveList<String> mList;
|
|
||||||
|
|
||||||
public FlashZip(Activity context, Uri uri, AdaptiveList<String> list) {
|
|
||||||
super(context);
|
super(context);
|
||||||
mUri = uri;
|
mUri = uri;
|
||||||
mList = list;
|
this.console = console;
|
||||||
|
this.logs = logs;
|
||||||
mCachedFile = new File(context.getCacheDir(), "install.zip");
|
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 {
|
private boolean unzipAndCheck() throws Exception {
|
||||||
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", false);
|
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", true);
|
||||||
List<String> ret = Utils.readFile(getShell(), mCheckFile.getPath());
|
List<String> ret = Utils.readFile(new File(mCachedFile.getParentFile(), "updater-script").getPath());
|
||||||
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
|
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
protected Integer doInBackground(Void... voids) {
|
protected Integer doInBackground(Void... voids) {
|
||||||
MagiskManager mm = getMagiskManager();
|
MagiskManager mm = MagiskManager.get();
|
||||||
if (mm == null) return -1;
|
|
||||||
try {
|
try {
|
||||||
mList.add("- Copying zip to temp directory");
|
console.add("- Copying zip to temp directory");
|
||||||
|
|
||||||
mCachedFile.delete();
|
mCachedFile.delete();
|
||||||
try (
|
try (
|
||||||
InputStream in = mm.getContentResolver().openInputStream(mUri);
|
InputStream in = mm.getContentResolver().openInputStream(mUri);
|
||||||
OutputStream out = new FileOutputStream(mCachedFile)
|
OutputStream out = new BufferedOutputStream(new FileOutputStream(mCachedFile))
|
||||||
) {
|
) {
|
||||||
if (in == null) throw new FileNotFoundException();
|
if (in == null) throw new FileNotFoundException();
|
||||||
byte buffer[] = new byte[1024];
|
InputStream buf= new BufferedInputStream(in);
|
||||||
int length;
|
Utils.inToOut(buf, out);
|
||||||
while ((length = in.read(buffer)) > 0)
|
|
||||||
out.write(buffer, 0, length);
|
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
mList.add("! Invalid Uri");
|
console.add("! Invalid Uri");
|
||||||
throw e;
|
throw e;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
mList.add("! Cannot copy to cache");
|
console.add("! Cannot copy to cache");
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
if (!unzipAndCheck()) return 0;
|
if (!unzipAndCheck()) return 0;
|
||||||
mList.add("- Installing " + mFilename);
|
console.add("- Installing " + Utils.getNameFromUri(mm, mUri));
|
||||||
getShell().su(mList,
|
Shell.getShell().run(console, logs,
|
||||||
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile +
|
"cd " + mCachedFile.getParent(),
|
||||||
" && echo 'Success!' || echo 'Failed!'"
|
"BOOTMODE=true sh update-binary dummy 1 " + mCachedFile + " || echo 'Failed!'"
|
||||||
);
|
);
|
||||||
if (TextUtils.equals(mList.get(mList.size() - 1), "Success!"))
|
|
||||||
return 1;
|
if (TextUtils.equals(console.get(console.size() - 1), "Failed!"))
|
||||||
|
return -1;
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return -1;
|
console.add("- All done!");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Integer result) {
|
protected void onPostExecute(Integer result) {
|
||||||
MagiskManager mm = getMagiskManager();
|
FlashActivity activity = (FlashActivity) getActivity();
|
||||||
if (mm == null) return;
|
Shell.su_raw(
|
||||||
getShell().su_raw(
|
|
||||||
"rm -rf " + mCachedFile.getParent(),
|
"rm -rf " + mCachedFile.getParent(),
|
||||||
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
|
"rm -rf " + Const.TMP_FOLDER_PATH
|
||||||
);
|
);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case -1:
|
case -1:
|
||||||
mList.add(mm.getString(R.string.install_error));
|
console.add("! Installation failed");
|
||||||
Utils.showUriSnack(getActivity(), mUri);
|
Utils.showUriSnack(getActivity(), mUri);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
mList.add(mm.getString(R.string.invalid_zip));
|
console.add("! This zip is not a Magisk Module!");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// Success
|
// Success
|
||||||
new LoadModules(mm).exec();
|
new LoadModules().exec();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
super.onPostExecute(result);
|
activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE);
|
||||||
|
activity.buttonPanel.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +1,145 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.topjohnwu.crypto.JarMap;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
|
||||||
public class HideManager extends ParallelTask<Void, Void, Boolean> {
|
public class HideManager extends ParallelTask<Void, Void, Boolean> {
|
||||||
|
|
||||||
public HideManager(Context context) {
|
private String genPackageName(String prefix, int length) {
|
||||||
super(context);
|
StringBuilder builder = new StringBuilder(length);
|
||||||
|
builder.append(prefix);
|
||||||
|
length -= prefix.length();
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
String base = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
String alpha = base + base.toUpperCase();
|
||||||
|
String full = alpha + "0123456789..........";
|
||||||
|
char next, prev = '\0';
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
if (prev == '.' || i == length - 1 || i == 0) {
|
||||||
|
next = alpha.charAt(random.nextInt(alpha.length()));
|
||||||
|
} else {
|
||||||
|
next = full.charAt(random.nextInt(full.length()));
|
||||||
|
}
|
||||||
|
builder.append(next);
|
||||||
|
prev = next;
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findOffset(byte buf[], byte pattern[]) {
|
||||||
|
int offset = -1;
|
||||||
|
for (int i = 0; i < buf.length - pattern.length; ++i) {
|
||||||
|
boolean match = true;
|
||||||
|
for (int j = 0; j < pattern.length; ++j) {
|
||||||
|
if (buf[i + j] != pattern[j]) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
offset = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It seems that AAPT sometimes generate another type of string format */
|
||||||
|
private boolean fallbackPatch(byte xml[], String from, String to) {
|
||||||
|
|
||||||
|
byte[] target = new byte[from.length() * 2 + 2];
|
||||||
|
for (int i = 0; i < from.length(); ++i) {
|
||||||
|
target[i * 2] = (byte) from.charAt(i);
|
||||||
|
}
|
||||||
|
int offset = findOffset(xml, target);
|
||||||
|
if (offset < 0)
|
||||||
|
return false;
|
||||||
|
byte[] dest = new byte[target.length - 2];
|
||||||
|
for (int i = 0; i < to.length(); ++i) {
|
||||||
|
dest[i * 2] = (byte) to.charAt(i);
|
||||||
|
}
|
||||||
|
System.arraycopy(dest, 0, xml, offset, dest.length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean findAndPatch(byte xml[], String from, String to) {
|
||||||
|
byte target[] = (from + '\0').getBytes();
|
||||||
|
int offset = findOffset(xml, target);
|
||||||
|
if (offset < 0)
|
||||||
|
return fallbackPatch(xml, from, to);
|
||||||
|
System.arraycopy(to.getBytes(), 0, xml, offset, to.length());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
getMagiskManager().toast(R.string.hide_manager_toast, Toast.LENGTH_SHORT);
|
MagiskManager.toast(R.string.hide_manager_toast, Toast.LENGTH_SHORT);
|
||||||
|
MagiskManager.toast(R.string.hide_manager_toast2, Toast.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(Void... voids) {
|
protected Boolean doInBackground(Void... voids) {
|
||||||
MagiskManager mm = getMagiskManager();
|
MagiskManager mm = MagiskManager.get();
|
||||||
if (mm == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Generate a new unhide app with random package name
|
// Generate a new unhide app with random package name
|
||||||
File unhideAPK = new File(Environment.getExternalStorageDirectory() + "/MagiskManager", "unhide.apk");
|
File repack = new File(Const.EXTERNAL_PATH, "repack.apk");
|
||||||
unhideAPK.getParentFile().mkdirs();
|
repack.getParentFile().mkdirs();
|
||||||
String pkg = ZipUtils.generateUnhide(mm, unhideAPK);
|
String pkg = genPackageName("com.", Const.ORIG_PKG_NAME.length());
|
||||||
|
|
||||||
// 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 {
|
try {
|
||||||
// Allow the application to gain root by default
|
// Read whole APK into memory
|
||||||
PackageManager pm = mm.getPackageManager();
|
JarMap apk = new JarMap(new FileInputStream(mm.getPackageCodePath()));
|
||||||
int uid = pm.getApplicationInfo(pkg, 0).uid;
|
JarEntry je = new JarEntry(Const.ANDROID_MANIFEST);
|
||||||
Policy policy = new Policy(uid, pm);
|
byte xml[] = apk.getRawData(je);
|
||||||
policy.policy = Policy.ALLOW;
|
|
||||||
policy.notification = false;
|
if (!findAndPatch(xml, Const.ORIG_PKG_NAME, pkg))
|
||||||
policy.logging = false;
|
return false;
|
||||||
mm.suDB.addPolicy(policy);
|
if (!findAndPatch(xml, Const.ORIG_PKG_NAME + ".provider", pkg + ".provider"))
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
return false;
|
||||||
|
|
||||||
|
// Write in changes
|
||||||
|
apk.getOutputStream(je).write(xml);
|
||||||
|
|
||||||
|
// Sign the APK
|
||||||
|
ZipUtils.signZip(apk, repack, false);
|
||||||
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide myself!
|
// Install the application
|
||||||
getShell().su_raw("pm hide " + mm.getPackageName());
|
|
||||||
|
List<String> ret = Shell.su(String.format(Locale.US,
|
||||||
|
"pm install --user %d %s >/dev/null && echo true || echo false",
|
||||||
|
mm.userId, repack));
|
||||||
|
repack.delete();
|
||||||
|
if (!Utils.isValidShellResponse(ret) || !Boolean.parseBoolean(ret.get(0)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mm.suDB.setStrings(Const.Key.SU_REQUESTER, pkg);
|
||||||
|
Shell.su_raw(String.format(Locale.US, "pm uninstall --user %d %s", mm.userId, mm.getPackageName()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Boolean b) {
|
protected void onPostExecute(Boolean b) {
|
||||||
MagiskManager mm = getMagiskManager();
|
|
||||||
if (mm == null)
|
|
||||||
return;
|
|
||||||
if (!b) {
|
if (!b) {
|
||||||
mm.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
MagiskManager.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
super.onPostExecute(b);
|
super.onPostExecute(b);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,45 +1,36 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.module.BaseModule;
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.container.ValueSortedMap;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.ValueSortedMap;
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class LoadModules extends ParallelTask<Void, Void, Void> {
|
public class LoadModules extends ParallelTask<Void, Void, Void> {
|
||||||
|
|
||||||
public LoadModules(Context context) {
|
private List<String> getModList() {
|
||||||
super(context);
|
String command = "ls -d " + Const.MAGISK_PATH() + "/* | grep -v lost+found";
|
||||||
|
return Shell.su(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
MagiskManager mm = getMagiskManager();
|
MagiskManager mm = MagiskManager.get();
|
||||||
if (mm == null) return null;
|
|
||||||
Logger.dev("LoadModules: Loading modules");
|
|
||||||
|
|
||||||
mm.moduleMap = new ValueSortedMap<>();
|
mm.moduleMap = new ValueSortedMap<>();
|
||||||
|
|
||||||
for (String path : Utils.getModList(getShell(), MagiskManager.MAGISK_PATH)) {
|
for (String path : getModList()) {
|
||||||
Logger.dev("LoadModules: Adding modules from " + path);
|
Module module = new Module(path);
|
||||||
try {
|
mm.moduleMap.put(module.getId(), module);
|
||||||
Module module = new Module(getShell(), path);
|
|
||||||
mm.moduleMap.put(module.getId(), module);
|
|
||||||
} catch (BaseModule.CacheModException ignored) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.dev("LoadModules: Data load done");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void v) {
|
protected void onPostExecute(Void v) {
|
||||||
MagiskManager mm = getMagiskManager();
|
MagiskManager.get().moduleLoadDone.publish();
|
||||||
if (mm == null) return;
|
|
||||||
mm.moduleLoadDone.publish();
|
|
||||||
super.onPostExecute(v);
|
super.onPostExecute(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Activity;
|
|||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
import com.topjohnwu.magisk.utils.WebService;
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ public class MarkDownWindow extends ParallelTask<Void, Void, String> {
|
|||||||
Node doc = parser.parse(md);
|
Node doc = parser.parse(md);
|
||||||
return String.format(
|
return String.format(
|
||||||
"<link rel='stylesheet' type='text/css' href='file:///android_asset/%s.css'/> %s",
|
"<link rel='stylesheet' type='text/css' href='file:///android_asset/%s.css'/> %s",
|
||||||
getMagiskManager().isDarkTheme ? "dark" : "light", renderer.render(doc));
|
MagiskManager.get().isDarkTheme ? "dark" : "light", renderer.render(doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,30 +1,19 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
|
public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
|
||||||
|
|
||||||
private WeakReference<Activity> weakActivity;
|
private WeakReference<Activity> weakActivity;
|
||||||
private WeakReference<MagiskManager> weakMagiskManager;
|
|
||||||
|
|
||||||
private Runnable callback = null;
|
private Runnable callback = null;
|
||||||
|
|
||||||
public ParallelTask() {}
|
public ParallelTask() {}
|
||||||
|
|
||||||
public ParallelTask(Context context) {
|
|
||||||
weakMagiskManager = new WeakReference<>(Utils.getMagiskManager(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ParallelTask(Activity context) {
|
public ParallelTask(Activity context) {
|
||||||
this((Context) context);
|
|
||||||
weakActivity = new WeakReference<>(context);
|
weakActivity = new WeakReference<>(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,15 +21,6 @@ public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<P
|
|||||||
return weakActivity.get();
|
return weakActivity.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MagiskManager getMagiskManager() {
|
|
||||||
return weakMagiskManager.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Shell getShell() {
|
|
||||||
MagiskManager magiskManager = getMagiskManager();
|
|
||||||
return magiskManager == null ? null : Shell.getShell(magiskManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public ParallelTask<Params, Progress, Result> exec(Params... params) {
|
public ParallelTask<Params, Progress, Result> exec(Params... params) {
|
||||||
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
|
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
|
||||||
|
|||||||
@@ -5,12 +5,15 @@ import android.app.Activity;
|
|||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Environment;
|
import android.os.Handler;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.FlashActivity;
|
import com.topjohnwu.magisk.FlashActivity;
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.container.InputStreamWrapper;
|
||||||
|
import com.topjohnwu.magisk.utils.Const;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
import com.topjohnwu.magisk.utils.WebService;
|
||||||
@@ -21,34 +24,60 @@ import java.io.BufferedOutputStream;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
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 ProgressDialog progressDialog;
|
private ProgressDialog progressDialog;
|
||||||
private boolean mInstall;
|
private boolean mInstall;
|
||||||
private String mLink, mFile;
|
private String mLink;
|
||||||
|
private File mFile;
|
||||||
|
private int progress = 0, total = -1;
|
||||||
|
private Handler mHandler;
|
||||||
|
|
||||||
public ProcessRepoZip(Activity context, String link, String filename, boolean install) {
|
public ProcessRepoZip(Activity context, String link, String filename, boolean install) {
|
||||||
super(context);
|
super(context);
|
||||||
mLink = link;
|
mLink = link;
|
||||||
mFile = Environment.getExternalStorageDirectory() + "/MagiskManager/" + filename;
|
mFile = new File(Const.EXTERNAL_PATH, filename);
|
||||||
mInstall = install;
|
mInstall = install;
|
||||||
|
mHandler = new Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeTopFolder(File input, File output) throws IOException {
|
||||||
|
JarEntry entry;
|
||||||
|
try (
|
||||||
|
JarInputStream in = new JarInputStream(new BufferedInputStream(new FileInputStream(input)));
|
||||||
|
JarOutputStream out = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(output)))
|
||||||
|
) {
|
||||||
|
String path;
|
||||||
|
while ((entry = in.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;
|
||||||
|
}
|
||||||
|
out.putNextEntry(new JarEntry(path));
|
||||||
|
Utils.inToOut(in, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
Activity activity = getActivity();
|
Activity activity = getActivity();
|
||||||
progressDialog = ProgressDialog.show(activity,
|
mFile.getParentFile().mkdirs();
|
||||||
activity.getString(R.string.zip_download_title),
|
progressDialog = ProgressDialog.show(activity, activity.getString(R.string.zip_download_title), activity.getString(R.string.zip_download_msg, 0));
|
||||||
activity.getString(R.string.zip_download_msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onProgressUpdate(Void... values) {
|
|
||||||
progressDialog.setTitle(R.string.zip_process_title);
|
|
||||||
progressDialog.setMessage(getActivity().getString(R.string.zip_process_msg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -56,40 +85,49 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
|||||||
Activity activity = getActivity();
|
Activity activity = getActivity();
|
||||||
if (activity == null) return null;
|
if (activity == null) return null;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Request zip from Internet
|
// Request zip from Internet
|
||||||
InputStream in = WebService.request(WebService.GET, mLink, null);
|
HttpURLConnection conn;
|
||||||
if (in == null) return false;
|
do {
|
||||||
in = new BufferedInputStream(in);
|
conn = WebService.request(mLink, null);
|
||||||
|
if (conn == null) return null;
|
||||||
|
total = conn.getContentLength();
|
||||||
|
if (total < 0)
|
||||||
|
conn.disconnect();
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
} while (true);
|
||||||
|
|
||||||
// Temp files
|
// Temp files
|
||||||
File temp1 = new File(activity.getCacheDir(), "1.zip");
|
File temp1 = new File(activity.getCacheDir(), "1.zip");
|
||||||
File temp2 = new File(temp1.getParentFile(), "2.zip");
|
File temp2 = new File(temp1.getParentFile(), "2.zip");
|
||||||
temp1.getParentFile().mkdir();
|
temp1.getParentFile().mkdir();
|
||||||
|
|
||||||
// First remove top folder in Github source zip, Web -> temp1
|
// First download the zip, Web -> temp1
|
||||||
ZipUtils.removeTopFolder(in, temp1);
|
try (
|
||||||
|
InputStream in = new BufferedInputStream(new ProgressInputStream(conn.getInputStream()));
|
||||||
publishProgress();
|
OutputStream out = new BufferedOutputStream(new FileOutputStream(temp1))
|
||||||
|
|
||||||
// Then sign the zip for the first time, temp1 -> temp2
|
|
||||||
ZipUtils.signZip(activity, temp1, temp2, false);
|
|
||||||
|
|
||||||
// Adjust the zip to prevent unzip issues, temp2 -> temp1
|
|
||||||
ZipUtils.zipAdjust(temp2.getPath(), temp1.getPath());
|
|
||||||
|
|
||||||
// Finally, sign the whole zip file again, temp1 -> temp2
|
|
||||||
ZipUtils.signZip(activity, temp1, temp2, true);
|
|
||||||
|
|
||||||
// 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];
|
Utils.inToOut(in, out);
|
||||||
int length;
|
in.close();
|
||||||
while ((length = source.read(buffer)) > 0)
|
|
||||||
out.write(buffer, 0, length);
|
|
||||||
}
|
}
|
||||||
|
conn.disconnect();
|
||||||
|
|
||||||
|
mHandler.post(() -> {
|
||||||
|
progressDialog.setTitle(R.string.zip_process_title);
|
||||||
|
progressDialog.setMessage(getActivity().getString(R.string.zip_process_msg));
|
||||||
|
});
|
||||||
|
|
||||||
|
// First remove top folder in Github source zip, temp1 -> temp2
|
||||||
|
removeTopFolder(temp1, temp2);
|
||||||
|
|
||||||
|
// Then sign the zip for the first time, temp2 -> temp1
|
||||||
|
ZipUtils.signZip(temp2, temp1, false);
|
||||||
|
|
||||||
|
// Adjust the zip to prevent unzip issues, temp1 -> temp2
|
||||||
|
ZipUtils.zipAdjust(temp1.getPath(), temp2.getPath());
|
||||||
|
|
||||||
|
// Finally, sign the whole zip file again, temp2 -> target
|
||||||
|
ZipUtils.signZip(temp2, mFile, true);
|
||||||
|
|
||||||
// Delete temp files
|
// Delete temp files
|
||||||
temp1.delete();
|
temp1.delete();
|
||||||
@@ -97,7 +135,6 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Logger.error("ProcessRepoZip: Error!");
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -108,24 +145,60 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
|||||||
Activity activity = getActivity();
|
Activity activity = getActivity();
|
||||||
if (activity == null) return;
|
if (activity == null) return;
|
||||||
progressDialog.dismiss();
|
progressDialog.dismiss();
|
||||||
Uri uri = Uri.fromFile(new File(mFile));
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
Uri uri = Uri.fromFile(mFile);
|
||||||
if (Shell.rootAccess() && mInstall) {
|
if (Shell.rootAccess() && mInstall) {
|
||||||
Intent intent = new Intent(getActivity(), FlashActivity.class);
|
Intent intent = new Intent(activity, FlashActivity.class);
|
||||||
intent.setData(uri).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP);
|
intent.setData(uri).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
} else {
|
} else {
|
||||||
Utils.showUriSnack(activity, uri);
|
Utils.showUriSnack(activity, uri);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Utils.getMagiskManager(activity).toast(R.string.process_error, Toast.LENGTH_LONG);
|
MagiskManager.toast(R.string.process_error, Toast.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
super.onPostExecute(result);
|
super.onPostExecute(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParallelTask<Void, Void, Boolean> exec(Void... voids) {
|
public ParallelTask<Void, Object, Boolean> exec(Void... voids) {
|
||||||
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, () -> super.exec(voids));
|
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||||
|
() -> super.exec(voids));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ProgressInputStream extends InputStreamWrapper {
|
||||||
|
|
||||||
|
ProgressInputStream(InputStream in) {
|
||||||
|
super(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDlProgress(int step) {
|
||||||
|
progress += step;
|
||||||
|
progressDialog.setMessage(getActivity().getString(R.string.zip_download_msg, (int) (100 * (double) progress / total + 0.5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized int read() throws IOException {
|
||||||
|
int b = super.read();
|
||||||
|
if (b > 0) {
|
||||||
|
mHandler.post(() -> updateDlProgress(1));
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
if (read > 0) {
|
||||||
|
mHandler.post(() -> updateDlProgress(read));
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user