mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-03-29 23:02:15 +00:00
Stop using platform provided DownloadManager
This commit is contained in:
parent
2a2e1236fc
commit
0241a50c6f
@ -70,8 +70,9 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
fullImplementation project(':utils')
|
|
||||||
implementation 'androidx.core:core:1.0.1'
|
implementation 'androidx.core:core:1.0.1'
|
||||||
|
fullImplementation project(':utils')
|
||||||
|
fullImplementation 'com.amitshekhar.android:android-networking:1.0.2'
|
||||||
fullImplementation 'androidx.appcompat:appcompat:1.0.2'
|
fullImplementation 'androidx.appcompat:appcompat:1.0.2'
|
||||||
fullImplementation "androidx.preference:preference:${rootProject.ext.androidXVersion}"
|
fullImplementation "androidx.preference:preference:${rootProject.ext.androidXVersion}"
|
||||||
fullImplementation "androidx.recyclerview:recyclerview:${rootProject.ext.androidXVersion}"
|
fullImplementation "androidx.recyclerview:recyclerview:${rootProject.ext.androidXVersion}"
|
||||||
|
3
app/proguard-rules.pro
vendored
3
app/proguard-rules.pro
vendored
@ -25,6 +25,9 @@
|
|||||||
# Snet extention
|
# Snet extention
|
||||||
-keepclassmembers class com.topjohnwu.magisk.utils.ISafetyNetHelper { *; }
|
-keepclassmembers class com.topjohnwu.magisk.utils.ISafetyNetHelper { *; }
|
||||||
|
|
||||||
|
# Fast Android Networking Library
|
||||||
|
-dontwarn okhttp3.**
|
||||||
|
|
||||||
# Strip logging
|
# Strip logging
|
||||||
-assumenosideeffects class com.topjohnwu.magisk.utils.Logger {
|
-assumenosideeffects class com.topjohnwu.magisk.utils.Logger {
|
||||||
public *** debug(...);
|
public *** debug(...);
|
||||||
|
@ -61,13 +61,14 @@ public class Const {
|
|||||||
public static final int MAGISK_UPDATE_NOTIFICATION_ID = 4;
|
public static final int MAGISK_UPDATE_NOTIFICATION_ID = 4;
|
||||||
public static final int APK_UPDATE_NOTIFICATION_ID = 5;
|
public static final int APK_UPDATE_NOTIFICATION_ID = 5;
|
||||||
public static final int DTBO_NOTIFICATION_ID = 7;
|
public static final int DTBO_NOTIFICATION_ID = 7;
|
||||||
|
public static final int DOWNLOAD_PROGRESS_ID = 8;
|
||||||
public static final String NOTIFICATION_CHANNEL = "magisk_notification";
|
public static final String NOTIFICATION_CHANNEL = "magisk_notification";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Url {
|
public static class Url {
|
||||||
public static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json";
|
public static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json";
|
||||||
public static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/beta.json";
|
public static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/beta.json";
|
||||||
public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed&page=%d";
|
public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed";
|
||||||
public static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s";
|
public static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s";
|
||||||
public static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip";
|
public static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip";
|
||||||
public static final String PAYPAL_URL = "https://www.paypal.me/topjohnwu";
|
public static final String PAYPAL_URL = "https://www.paypal.me/topjohnwu";
|
||||||
@ -92,7 +93,7 @@ public class Const {
|
|||||||
|
|
||||||
// intents
|
// intents
|
||||||
public static final String OPEN_SECTION = "section";
|
public static final String OPEN_SECTION = "section";
|
||||||
public static final String INTENT_SET_FILENAME = "filename";
|
public static final String INTENT_SET_NAME = "filename";
|
||||||
public static final String INTENT_SET_LINK = "link";
|
public static final String INTENT_SET_LINK = "link";
|
||||||
public static final String FLASH_ACTION = "action";
|
public static final String FLASH_ACTION = "action";
|
||||||
public static final String FLASH_SET_BOOT = "boot";
|
public static final String FLASH_SET_BOOT = "boot";
|
||||||
|
@ -32,7 +32,7 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Void> {
|
|||||||
private void dlSnet() throws Exception {
|
private void dlSnet() throws Exception {
|
||||||
Shell.sh("rm -rf " + dexPath.getParent()).exec();
|
Shell.sh("rm -rf " + dexPath.getParent()).exec();
|
||||||
dexPath.getParentFile().mkdir();
|
dexPath.getParentFile().mkdir();
|
||||||
HttpURLConnection conn = WebService.mustRequest(Data.snetLink, null);
|
HttpURLConnection conn = WebService.mustRequest(Data.snetLink);
|
||||||
try (
|
try (
|
||||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath));
|
OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath));
|
||||||
InputStream in = new BufferedInputStream(conn.getInputStream())) {
|
InputStream in = new BufferedInputStream(conn.getInputStream())) {
|
||||||
|
@ -5,9 +5,9 @@ import android.os.AsyncTask;
|
|||||||
import com.topjohnwu.magisk.BuildConfig;
|
import com.topjohnwu.magisk.BuildConfig;
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.utils.NotificationMgr;
|
import com.topjohnwu.magisk.utils.Notifications;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@ -46,13 +46,13 @@ public class CheckUpdates {
|
|||||||
String jsonStr = "";
|
String jsonStr = "";
|
||||||
switch (Data.updateChannel) {
|
switch (Data.updateChannel) {
|
||||||
case Const.Value.STABLE_CHANNEL:
|
case Const.Value.STABLE_CHANNEL:
|
||||||
jsonStr = WebService.getString(Const.Url.STABLE_URL);
|
jsonStr = Utils.dlString(Const.Url.STABLE_URL);
|
||||||
break;
|
break;
|
||||||
case Const.Value.BETA_CHANNEL:
|
case Const.Value.BETA_CHANNEL:
|
||||||
jsonStr = WebService.getString(Const.Url.BETA_URL);
|
jsonStr = Utils.dlString(Const.Url.BETA_URL);
|
||||||
break;
|
break;
|
||||||
case Const.Value.CUSTOM_CHANNEL:
|
case Const.Value.CUSTOM_CHANNEL:
|
||||||
jsonStr = WebService.getString(Data.MM().prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
jsonStr = Utils.dlString(Data.MM().prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,9 +89,9 @@ public class CheckUpdates {
|
|||||||
fetchUpdates();
|
fetchUpdates();
|
||||||
if (cb != null) {
|
if (cb != null) {
|
||||||
if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) {
|
if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) {
|
||||||
NotificationMgr.managerUpdate();
|
Notifications.managerUpdate();
|
||||||
} else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) {
|
} else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) {
|
||||||
NotificationMgr.magiskUpdate();
|
Notifications.magiskUpdate();
|
||||||
}
|
}
|
||||||
cb.run();
|
cb.run();
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
|
|||||||
|
|
||||||
if (!ShellUtils.checkSum("MD5", zip, Data.magiskMD5)) {
|
if (!ShellUtils.checkSum("MD5", zip, Data.magiskMD5)) {
|
||||||
console.add("- Downloading zip");
|
console.add("- Downloading zip");
|
||||||
HttpURLConnection conn = WebService.mustRequest(Data.magiskLink, null);
|
HttpURLConnection conn = WebService.mustRequest(Data.magiskLink);
|
||||||
buf = new BufferedInputStream(new ProgressStream(conn), conn.getContentLength());
|
buf = new BufferedInputStream(new ProgressStream(conn), conn.getContentLength());
|
||||||
buf.mark(conn.getContentLength() + 1);
|
buf.mark(conn.getContentLength() + 1);
|
||||||
try (OutputStream out = new FileOutputStream(zip)) {
|
try (OutputStream out = new FileOutputStream(zip)) {
|
||||||
|
@ -6,7 +6,7 @@ import android.webkit.WebView;
|
|||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
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.Utils;
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
|
|
||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
@ -43,7 +43,7 @@ public class MarkDownWindow extends ParallelTask<Void, Void, String> {
|
|||||||
MagiskManager mm = Data.MM();
|
MagiskManager mm = Data.MM();
|
||||||
String md;
|
String md;
|
||||||
if (mUrl != null) {
|
if (mUrl != null) {
|
||||||
md = WebService.getString(mUrl);
|
md = Utils.dlString(mUrl);
|
||||||
} else {
|
} else {
|
||||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||||
ShellUtils.pump(is, out);
|
ShellUtils.pump(is, out);
|
||||||
|
@ -93,7 +93,7 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
|
|||||||
if (activity == null) return null;
|
if (activity == null) return null;
|
||||||
try {
|
try {
|
||||||
// Request zip from Internet
|
// Request zip from Internet
|
||||||
HttpURLConnection conn = WebService.mustRequest(mRepo.getZipUrl(), null);
|
HttpURLConnection conn = WebService.mustRequest(mRepo.getZipUrl());
|
||||||
total = conn.getContentLength();
|
total = conn.getContentLength();
|
||||||
|
|
||||||
// Temp files
|
// Temp files
|
||||||
@ -101,7 +101,7 @@ public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
|
|||||||
File temp2 = new File(temp1.getParentFile(), "2.zip");
|
File temp2 = new File(temp1.getParentFile(), "2.zip");
|
||||||
temp1.getParentFile().mkdir();
|
temp1.getParentFile().mkdir();
|
||||||
|
|
||||||
// First download the zip, Web -> temp1
|
// First upgrade the zip, Web -> temp1
|
||||||
try (
|
try (
|
||||||
InputStream in = new BufferedInputStream(new ProgressInputStream(conn.getInputStream()));
|
InputStream in = new BufferedInputStream(new ProgressInputStream(conn.getInputStream()));
|
||||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(temp1))
|
OutputStream out = new BufferedOutputStream(new FileOutputStream(temp1))
|
||||||
|
@ -3,14 +3,15 @@ package com.topjohnwu.magisk.asyncs;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import com.androidnetworking.AndroidNetworking;
|
||||||
|
import com.androidnetworking.common.ANRequest;
|
||||||
|
import com.androidnetworking.common.ANResponse;
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.container.Repo;
|
import com.topjohnwu.magisk.container.Repo;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@ -22,9 +23,7 @@ import java.text.ParseException;
|
|||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@ -32,40 +31,36 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class UpdateRepos {
|
public class UpdateRepos {
|
||||||
|
|
||||||
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
|
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
|
||||||
private static final int CORE_POOL_SIZE = Math.max(2, CPU_COUNT - 1);
|
private static final int CORE_POOL_SIZE = Math.max(2, CPU_COUNT - 1);
|
||||||
private static final DateFormat dateFormat;
|
private static final DateFormat dateFormat;
|
||||||
|
|
||||||
|
private MagiskManager mm;
|
||||||
|
private Set<String> cached;
|
||||||
|
private ExecutorService threadPool;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private MagiskManager mm;
|
|
||||||
private Set<String> cached;
|
|
||||||
private ExecutorService threadPool;
|
|
||||||
|
|
||||||
public UpdateRepos() {
|
public UpdateRepos() {
|
||||||
mm = Data.MM();
|
mm = Data.MM();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitTasks() {
|
private void waitTasks() {
|
||||||
threadPool.shutdown();
|
threadPool.shutdown();
|
||||||
try {
|
while (true) {
|
||||||
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
try {
|
||||||
} catch (InterruptedException ignored) {}
|
if (threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS))
|
||||||
|
break;
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean loadJSON(String jsonString) throws JSONException, ParseException {
|
private void loadJSON(JSONArray array) throws JSONException, ParseException {
|
||||||
JSONArray jsonArray = new JSONArray(jsonString);
|
for (int i = 0; i < array.length(); i++) {
|
||||||
|
JSONObject rawRepo = array.getJSONObject(i);
|
||||||
// Empty page, halt
|
|
||||||
if (jsonArray.length() == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = 0; i < jsonArray.length(); i++) {
|
|
||||||
JSONObject rawRepo = jsonArray.getJSONObject(i);
|
|
||||||
String id = rawRepo.getString("name");
|
String id = rawRepo.getString("name");
|
||||||
Date date = dateFormat.parse(rawRepo.getString("pushed_at"));
|
Date date = dateFormat.parse(rawRepo.getString("pushed_at"));
|
||||||
threadPool.execute(() -> {
|
threadPool.execute(() -> {
|
||||||
@ -83,42 +78,50 @@ public class UpdateRepos {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We sort repos by last push, which means that we only need to check whether the
|
/* We sort repos by last push, which means that we only need to check whether the
|
||||||
* first page is updated to determine whether the online repo database is changed
|
* first page is updated to determine whether the online repo database is changed
|
||||||
*/
|
*/
|
||||||
private boolean loadPage(int page) {
|
private boolean loadPage(int page) {
|
||||||
Map<String, String> header = new HashMap<>();
|
ANRequest.GetRequestBuilder req = AndroidNetworking.get(Const.Url.REPO_URL)
|
||||||
if (page == 0)
|
.addQueryParameter("page", String.valueOf(page + 1));
|
||||||
header.put(Const.Key.IF_NONE_MATCH, mm.prefs.getString(Const.Key.ETAG_KEY, ""));
|
if (page == 0) {
|
||||||
String url = Utils.fmt(Const.Url.REPO_URL, page + 1);
|
String etag = mm.prefs.getString(Const.Key.ETAG_KEY, null);
|
||||||
|
if (etag != null)
|
||||||
|
req.addHeaders(Const.Key.IF_NONE_MATCH, etag);
|
||||||
|
}
|
||||||
|
ANResponse<JSONArray> res = req.build().executeForJSONArray();
|
||||||
|
if (res.getOkHttpResponse().code() == HttpURLConnection.HTTP_NOT_MODIFIED)
|
||||||
|
return false;
|
||||||
|
// Current page is the last page
|
||||||
|
if (res.getResult() == null || res.getResult().length() == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpURLConnection conn = WebService.request(url, header);
|
loadJSON(res.getResult());
|
||||||
// No updates
|
} catch (JSONException | ParseException e) {
|
||||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED)
|
|
||||||
return false;
|
|
||||||
// Current page is the last page
|
|
||||||
if (!loadJSON(WebService.getString(conn)))
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Should not happen, but if exception occurs, page load fails
|
// Should not happen, but if exception occurs, page load fails
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update ETAG
|
// Update ETAG
|
||||||
if (page == 0) {
|
if (page == 0) {
|
||||||
String etag = header.get(Const.Key.ETAG_KEY);
|
String etag = res.getOkHttpResponse().header(Const.Key.ETAG_KEY);
|
||||||
etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1);
|
if (etag != null) {
|
||||||
mm.prefs.edit().putString(Const.Key.ETAG_KEY, etag).apply();
|
etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1);
|
||||||
|
mm.prefs.edit().putString(Const.Key.ETAG_KEY, etag).apply();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String links = header.get(Const.Key.LINK_KEY);
|
String links = res.getOkHttpResponse().header(Const.Key.LINK_KEY);
|
||||||
return links == null || !links.contains("next") || loadPage(page + 1);
|
return links == null || !links.contains("next") || loadPage(page + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean loadPages() {
|
||||||
|
return loadPage(0);
|
||||||
|
}
|
||||||
|
|
||||||
private void fullReload() {
|
private void fullReload() {
|
||||||
Cursor c = mm.repoDB.getRawCursor();
|
Cursor c = mm.repoDB.getRawCursor();
|
||||||
while (c.moveToNext()) {
|
while (c.moveToNext()) {
|
||||||
@ -142,7 +145,7 @@ public class UpdateRepos {
|
|||||||
cached = Collections.synchronizedSet(mm.repoDB.getRepoIDSet());
|
cached = Collections.synchronizedSet(mm.repoDB.getRepoIDSet());
|
||||||
threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
|
threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
|
||||||
|
|
||||||
if (loadPage(0)) {
|
if (loadPages()) {
|
||||||
waitTasks();
|
waitTasks();
|
||||||
// The leftover cached means they are removed from online repo
|
// The leftover cached means they are removed from online repo
|
||||||
mm.repoDB.removeRepo(cached);
|
mm.repoDB.removeRepo(cached);
|
||||||
|
@ -2,35 +2,37 @@ package com.topjohnwu.magisk.components;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.NoUIActivity;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
import com.topjohnwu.magisk.utils.LocaleManager;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StyleRes;
|
import androidx.annotation.StyleRes;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
public abstract class FlavorActivity extends AppCompatActivity implements Topic.AutoSubscriber {
|
public abstract class BaseActivity extends AppCompatActivity implements Topic.AutoSubscriber {
|
||||||
|
|
||||||
|
public static final String INTENT_PERM = "perm_dialog";
|
||||||
|
|
||||||
|
protected static Runnable permissionGrantCallback;
|
||||||
|
static int[] EMPTY_INT_ARRAY = new int[0];
|
||||||
|
|
||||||
private ActivityResultListener activityResultListener;
|
private ActivityResultListener activityResultListener;
|
||||||
static int[] EMPTY_INT_ARRAY = new int[0];
|
|
||||||
public MagiskManager mm;
|
public MagiskManager mm;
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void attachBaseContext(Context base) {
|
|
||||||
super.attachBaseContext(base);
|
|
||||||
Configuration config = base.getResources().getConfiguration();
|
|
||||||
config.setLocale(LocaleManager.locale);
|
|
||||||
applyOverrideConfiguration(config);
|
|
||||||
mm = Data.MM();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getSubscribedTopics() {
|
public int[] getSubscribedTopics() {
|
||||||
return EMPTY_INT_ARRAY;
|
return EMPTY_INT_ARRAY;
|
||||||
@ -41,6 +43,15 @@ public abstract class FlavorActivity extends AppCompatActivity implements Topic.
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void attachBaseContext(Context base) {
|
||||||
|
super.attachBaseContext(base);
|
||||||
|
Configuration config = base.getResources().getConfiguration();
|
||||||
|
config.setLocale(LocaleManager.locale);
|
||||||
|
applyOverrideConfiguration(config);
|
||||||
|
mm = Data.MM();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
Topic.subscribe(this);
|
Topic.subscribe(this);
|
||||||
@ -48,6 +59,9 @@ public abstract class FlavorActivity extends AppCompatActivity implements Topic.
|
|||||||
setTheme(getDarkTheme());
|
setTheme(getDarkTheme());
|
||||||
}
|
}
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
String[] perms = getIntent().getStringArrayExtra(INTENT_PERM);
|
||||||
|
if (perms != null)
|
||||||
|
ActivityCompat.requestPermissions(this, perms, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,6 +84,34 @@ public abstract class FlavorActivity extends AppCompatActivity implements Topic.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void runWithPermission(Context context, String[] permissions, Runnable callback) {
|
||||||
|
boolean granted = true;
|
||||||
|
for (String perm : permissions) {
|
||||||
|
if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED)
|
||||||
|
granted = false;
|
||||||
|
}
|
||||||
|
if (granted) {
|
||||||
|
Download.EXTERNAL_PATH.mkdirs();
|
||||||
|
callback.run();
|
||||||
|
} else {
|
||||||
|
// Passed in context should be an activity if not granted, need to show dialog!
|
||||||
|
permissionGrantCallback = callback;
|
||||||
|
if (!(context instanceof BaseActivity)) {
|
||||||
|
// Start NoUIActivity to show dialog
|
||||||
|
Intent intent = new Intent(context, Data.classMap.get(NoUIActivity.class));
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.putExtra(INTENT_PERM, permissions);
|
||||||
|
context.startActivity(intent);
|
||||||
|
} else {
|
||||||
|
ActivityCompat.requestPermissions((BaseActivity) context, permissions, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runWithPermission(String[] permissions, Runnable callback) {
|
||||||
|
runWithPermission(this, permissions, callback);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (activityResultListener != null)
|
if (activityResultListener != null)
|
||||||
@ -82,6 +124,23 @@ public abstract class FlavorActivity extends AppCompatActivity implements Topic.
|
|||||||
super.startActivityForResult(intent, requestCode);
|
super.startActivityForResult(intent, requestCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
|
boolean grant = true;
|
||||||
|
for (int result : grantResults) {
|
||||||
|
if (result != PackageManager.PERMISSION_GRANTED)
|
||||||
|
grant = false;
|
||||||
|
}
|
||||||
|
if (grant) {
|
||||||
|
if (permissionGrantCallback != null) {
|
||||||
|
permissionGrantCallback.run();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, R.string.no_rw_storage, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
permissionGrantCallback = null;
|
||||||
|
}
|
||||||
|
|
||||||
public interface ActivityResultListener {
|
public interface ActivityResultListener {
|
||||||
void onActivityResult(int requestCode, int resultCode, Intent data);
|
void onActivityResult(int requestCode, int resultCode, Intent data);
|
||||||
}
|
}
|
@ -52,6 +52,6 @@ public class BaseFragment extends Fragment implements Topic.AutoSubscriber {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getSubscribedTopics() {
|
public int[] getSubscribedTopics() {
|
||||||
return FlavorActivity.EMPTY_INT_ARRAY;
|
return BaseActivity.EMPTY_INT_ARRAY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,17 @@ package com.topjohnwu.magisk.components;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.androidnetworking.AndroidNetworking;
|
||||||
|
import com.androidnetworking.error.ANError;
|
||||||
|
import com.androidnetworking.interfaces.DownloadListener;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.FlashActivity;
|
import com.topjohnwu.magisk.FlashActivity;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
@ -28,31 +29,10 @@ class InstallMethodDialog extends AlertDialog.Builder {
|
|||||||
Intent intent;
|
Intent intent;
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case 1:
|
case 1:
|
||||||
Utils.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG);
|
patchBoot(activity);
|
||||||
intent = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*");
|
|
||||||
activity.runWithPermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, () ->
|
|
||||||
activity.startActivityForResult(intent, Const.ID.SELECT_BOOT,
|
|
||||||
(requestCode, resultCode, data) -> {
|
|
||||||
if (requestCode == Const.ID.SELECT_BOOT &&
|
|
||||||
resultCode == Activity.RESULT_OK && data != null) {
|
|
||||||
Intent i = new Intent(activity, Data.classMap.get(FlashActivity.class))
|
|
||||||
.putExtra(Const.Key.FLASH_SET_BOOT, data.getData())
|
|
||||||
.putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT);
|
|
||||||
activity.startActivity(i);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
String filename = Utils.fmt("Magisk-v%s(%d).zip",
|
downloadOnly(activity);
|
||||||
Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode);
|
|
||||||
Download.receive(activity, new DownloadReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onDownloadDone(Context context, Uri uri) {
|
|
||||||
SnackbarMaker.showUri(activity, uri);
|
|
||||||
}
|
|
||||||
}, Data.magiskLink, filename);
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
intent = new Intent(activity, Data.classMap.get(FlashActivity.class))
|
intent = new Intent(activity, Data.classMap.get(FlashActivity.class))
|
||||||
@ -60,20 +40,65 @@ class InstallMethodDialog extends AlertDialog.Builder {
|
|||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
new CustomAlertDialog(activity)
|
installInactiveSlot(activity);
|
||||||
.setTitle(R.string.warning)
|
|
||||||
.setMessage(R.string.install_inactive_slot_msg)
|
|
||||||
.setCancelable(true)
|
|
||||||
.setPositiveButton(R.string.yes, (d, i) -> {
|
|
||||||
Intent it = new Intent(activity, Data.classMap.get(FlashActivity.class))
|
|
||||||
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_INACTIVE_SLOT);
|
|
||||||
activity.startActivity(it);
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.no_thanks, null)
|
|
||||||
.show();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void patchBoot(BaseActivity a) {
|
||||||
|
Utils.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG);
|
||||||
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*");
|
||||||
|
a.runWithPermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, () ->
|
||||||
|
a.startActivityForResult(intent, Const.ID.SELECT_BOOT,
|
||||||
|
(requestCode, resultCode, data) -> {
|
||||||
|
if (requestCode == Const.ID.SELECT_BOOT &&
|
||||||
|
resultCode == Activity.RESULT_OK && data != null) {
|
||||||
|
Intent i = new Intent(a, Data.classMap.get(FlashActivity.class))
|
||||||
|
.putExtra(Const.Key.FLASH_SET_BOOT, data.getData())
|
||||||
|
.putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT);
|
||||||
|
a.startActivity(i);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadOnly(BaseActivity a) {
|
||||||
|
a.runWithPermission(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, () -> {
|
||||||
|
String filename = Utils.fmt("Magisk-v%s(%d).zip",
|
||||||
|
Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode);
|
||||||
|
NotificationProgress progress = new NotificationProgress(filename);
|
||||||
|
AndroidNetworking
|
||||||
|
.download(Data.magiskLink, Download.EXTERNAL_PATH.getPath(), filename)
|
||||||
|
.build()
|
||||||
|
.setDownloadProgressListener(progress)
|
||||||
|
.startDownload(new DownloadListener() {
|
||||||
|
@Override
|
||||||
|
public void onDownloadComplete() {
|
||||||
|
progress.defaultDone();
|
||||||
|
SnackbarMaker.make(a,
|
||||||
|
a.getString(R.string.internal_storage, "/Download/" + filename),
|
||||||
|
Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ANError anError) {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void installInactiveSlot(BaseActivity activity) {
|
||||||
|
new CustomAlertDialog(activity)
|
||||||
|
.setTitle(R.string.warning)
|
||||||
|
.setMessage(R.string.install_inactive_slot_msg)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setPositiveButton(R.string.yes, (d, i) -> {
|
||||||
|
Intent intent = new Intent(activity, Data.classMap.get(FlashActivity.class))
|
||||||
|
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_INACTIVE_SLOT);
|
||||||
|
activity.startActivity(intent);
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
package com.topjohnwu.magisk.components;
|
package com.topjohnwu.magisk.components;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
||||||
import com.topjohnwu.magisk.receivers.ManagerUpdate;
|
import com.topjohnwu.magisk.utils.DlInstallManager;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@ -19,19 +16,13 @@ public class ManagerInstallDialog extends CustomAlertDialog {
|
|||||||
public ManagerInstallDialog(@NonNull BaseActivity activity) {
|
public ManagerInstallDialog(@NonNull BaseActivity activity) {
|
||||||
super(activity);
|
super(activity);
|
||||||
MagiskManager mm = Data.MM();
|
MagiskManager mm = Data.MM();
|
||||||
String filename = Utils.fmt("MagiskManager-v%s(%d).apk",
|
String name = Utils.fmt("MagiskManager v%s(%d)",
|
||||||
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
||||||
setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name)));
|
setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name)));
|
||||||
setMessage(mm.getString(R.string.repo_install_msg, filename));
|
setMessage(mm.getString(R.string.repo_install_msg, name));
|
||||||
setCancelable(true);
|
setCancelable(true);
|
||||||
setPositiveButton(R.string.install, (d, i) -> activity.runWithPermission(
|
setPositiveButton(R.string.install, (d, i) -> DlInstallManager.upgrade(name));
|
||||||
new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, () -> {
|
setNegativeButton(R.string.no_thanks, null);
|
||||||
Intent intent = new Intent(mm, Data.classMap.get(ManagerUpdate.class));
|
|
||||||
intent.putExtra(Const.Key.INTENT_SET_LINK, Data.managerLink);
|
|
||||||
intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename);
|
|
||||||
mm.sendBroadcast(intent);
|
|
||||||
}))
|
|
||||||
.setNegativeButton(R.string.no_thanks, null);
|
|
||||||
if (!TextUtils.isEmpty(Data.managerNoteLink)) {
|
if (!TextUtils.isEmpty(Data.managerNoteLink)) {
|
||||||
setNeutralButton(R.string.app_changelog, (d, i) ->
|
setNeutralButton(R.string.app_changelog, (d, i) ->
|
||||||
new MarkDownWindow(activity, null, Data.managerNoteLink).exec());
|
new MarkDownWindow(activity, null, Data.managerNoteLink).exec());
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.topjohnwu.magisk.components;
|
||||||
|
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.androidnetworking.interfaces.DownloadProgressListener;
|
||||||
|
import com.topjohnwu.magisk.Const;
|
||||||
|
import com.topjohnwu.magisk.Data;
|
||||||
|
import com.topjohnwu.magisk.utils.Notifications;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
|
import androidx.core.app.NotificationCompat;
|
||||||
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
|
|
||||||
|
public class NotificationProgress implements DownloadProgressListener {
|
||||||
|
|
||||||
|
private NotificationManagerCompat mgr;
|
||||||
|
private NotificationCompat.Builder builder;
|
||||||
|
private long prevTime;
|
||||||
|
|
||||||
|
public NotificationProgress(String title) {
|
||||||
|
mgr = NotificationManagerCompat.from(Data.MM());
|
||||||
|
builder = Notifications.progress(title);
|
||||||
|
mgr.notify(Const.ID.DOWNLOAD_PROGRESS_ID, builder.build());
|
||||||
|
prevTime = System.currentTimeMillis();
|
||||||
|
Utils.toast("Downloading " + title, Toast.LENGTH_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProgress(long bytesDownloaded, long totalBytes) {
|
||||||
|
long cur = System.currentTimeMillis();
|
||||||
|
if (cur - prevTime >= 1000) {
|
||||||
|
prevTime = cur;
|
||||||
|
builder.setProgress((int) totalBytes, (int) bytesDownloaded, false);
|
||||||
|
builder.setContentText(bytesDownloaded * 100 / totalBytes + "%");
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationCompat.Builder getBuilder() {
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
mgr.notify(Const.ID.DOWNLOAD_PROGRESS_ID, builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void defaultDone() {
|
||||||
|
builder.setProgress(0, 0, false);
|
||||||
|
builder.setContentText("Download done");
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
@ -2,29 +2,29 @@ package com.topjohnwu.magisk.components;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.androidnetworking.AndroidNetworking;
|
||||||
|
import com.androidnetworking.error.ANError;
|
||||||
|
import com.androidnetworking.interfaces.DownloadListener;
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
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.receivers.DownloadReceiver;
|
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
public class UninstallDialog extends CustomAlertDialog {
|
public class UninstallDialog extends CustomAlertDialog {
|
||||||
|
|
||||||
public UninstallDialog(@NonNull Activity activity) {
|
public UninstallDialog(@NonNull Activity activity) {
|
||||||
super(activity);
|
super(activity);
|
||||||
MagiskManager mm = Data.MM();
|
|
||||||
setTitle(R.string.uninstall_magisk_title);
|
setTitle(R.string.uninstall_magisk_title);
|
||||||
setMessage(R.string.uninstall_magisk_msg);
|
setMessage(R.string.uninstall_magisk_msg);
|
||||||
setNeutralButton(R.string.restore_img, (d, i) -> {
|
setNeutralButton(R.string.restore_img, (d, i) -> {
|
||||||
@ -41,17 +41,27 @@ public class UninstallDialog extends CustomAlertDialog {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (!TextUtils.isEmpty(Data.uninstallerLink)) {
|
if (!TextUtils.isEmpty(Data.uninstallerLink)) {
|
||||||
setPositiveButton(R.string.complete_uninstall, (d, i) ->
|
setPositiveButton(R.string.complete_uninstall, (d, i) -> {
|
||||||
Download.receive(activity, new DownloadReceiver() {
|
File zip = new File(activity.getFilesDir(), "uninstaller.zip");
|
||||||
|
NotificationProgress progress = new NotificationProgress(zip.getName());
|
||||||
|
AndroidNetworking.download(Data.uninstallerLink, zip.getParent(), zip.getName())
|
||||||
|
.build()
|
||||||
|
.setDownloadProgressListener(progress)
|
||||||
|
.startDownload(new DownloadListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onDownloadDone(Context context, Uri uri) {
|
public void onDownloadComplete() {
|
||||||
Intent intent = new Intent(context, Data.classMap.get(FlashActivity.class))
|
progress.defaultDone();
|
||||||
|
Intent intent = new Intent(activity, Data.classMap.get(FlashActivity.class))
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
.setData(uri)
|
.setData(Uri.fromFile(zip))
|
||||||
.putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL);
|
.putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL);
|
||||||
context.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
}
|
}
|
||||||
}, Data.uninstallerLink, "magisk-uninstaller.zip"));
|
|
||||||
|
@Override
|
||||||
|
public void onError(ANError anError) {}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import com.topjohnwu.magisk.Const;
|
|||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -26,7 +25,7 @@ public class Repo extends BaseModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update() throws IllegalRepoException {
|
public void update() throws IllegalRepoException {
|
||||||
String props[] = Utils.dos2unix(WebService.getString(getManifestUrl())).split("\\n");
|
String props[] = Utils.dlString(getPropUrl()).split("\\n");
|
||||||
try {
|
try {
|
||||||
parseProps(props);
|
parseProps(props);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
@ -57,7 +56,7 @@ public class Repo extends BaseModule {
|
|||||||
return String.format(Const.Url.ZIP_URL, getId());
|
return String.format(Const.Url.ZIP_URL, getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getManifestUrl() {
|
public String getPropUrl() {
|
||||||
return String.format(Const.Url.FILE_URL, getId(), "module.prop");
|
return String.format(Const.Url.FILE_URL, getId(), "module.prop");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ public class ModulesFragment extends BaseFragment implements Topic.Subscriber {
|
|||||||
Shell.su("/system/bin/reboot bootloader").submit();
|
Shell.su("/system/bin/reboot bootloader").submit();
|
||||||
return true;
|
return true;
|
||||||
case R.id.reboot_download:
|
case R.id.reboot_download:
|
||||||
Shell.su("/system/bin/reboot download").submit();
|
Shell.su("/system/bin/reboot upgrade").submit();
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package com.topjohnwu.magisk.fragments;
|
package com.topjohnwu.magisk.fragments;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -18,15 +16,13 @@ import com.topjohnwu.magisk.MagiskManager;
|
|||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
||||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
import com.topjohnwu.magisk.utils.DlInstallManager;
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
import com.topjohnwu.magisk.utils.LocaleManager;
|
||||||
import com.topjohnwu.magisk.utils.RootUtils;
|
|
||||||
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 com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -85,23 +81,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
});
|
});
|
||||||
Preference restoreManager = findPreference("restore");
|
Preference restoreManager = findPreference("restore");
|
||||||
restoreManager.setOnPreferenceClickListener(pref -> {
|
restoreManager.setOnPreferenceClickListener(pref -> {
|
||||||
Download.receive(
|
DlInstallManager.restore();
|
||||||
requireActivity(), new DownloadReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onDownloadDone(Context context, Uri uri) {
|
|
||||||
Data.exportPrefs();
|
|
||||||
Shell.su("cp " + uri.getPath() + " /data/local/tmp/manager.apk").exec();
|
|
||||||
if (ShellUtils.fastCmdResult("pm install /data/local/tmp/manager.apk")) {
|
|
||||||
Shell.su("rm -f /data/local/tmp/manager.apk").exec();
|
|
||||||
RootUtils.rmAndLaunch(context.getPackageName(), Const.ORIG_PKG_NAME);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Shell.su("rm -f /data/local/tmp/manager.apk").exec();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Data.managerLink,
|
|
||||||
Utils.fmt("MagiskManager-v%s.apk", Data.remoteManagerVersionString)
|
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
findPreference("clear").setOnPreferenceClickListener(pref -> {
|
findPreference("clear").setOnPreferenceClickListener(pref -> {
|
||||||
|
@ -3,47 +3,16 @@ package com.topjohnwu.magisk.receivers;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.DlInstallManager;
|
||||||
import com.topjohnwu.utils.JarMap;
|
|
||||||
import com.topjohnwu.utils.SignAPK;
|
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
|
|
||||||
public class ManagerUpdate extends BroadcastReceiver {
|
public class ManagerUpdate extends BroadcastReceiver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Download.receive(
|
Data.managerLink = intent.getStringExtra(Const.Key.INTENT_SET_LINK);
|
||||||
context, new PatchedInstall(),
|
DlInstallManager.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME));
|
||||||
intent.getStringExtra(Const.Key.INTENT_SET_LINK),
|
|
||||||
intent.getStringExtra(Const.Key.INTENT_SET_FILENAME)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PatchedInstall extends ManagerInstall {
|
|
||||||
@Override
|
|
||||||
public void onDownloadDone(Context context, Uri uri) {
|
|
||||||
if (!context.getPackageName().equals(Const.ORIG_PKG_NAME)) {
|
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
|
||||||
String orig = uri.getPath();
|
|
||||||
String patch = orig.substring(0, orig.lastIndexOf('.')) + "-patched.apk";
|
|
||||||
try {
|
|
||||||
JarMap apk = new JarMap(orig);
|
|
||||||
PatchAPK.patchPackageID(apk, Const.ORIG_PKG_NAME, context.getPackageName());
|
|
||||||
SignAPK.sign(apk, new BufferedOutputStream(new FileOutputStream(patch)));
|
|
||||||
super.onDownloadDone(context, Uri.fromFile(new File(patch)));
|
|
||||||
} catch (Exception ignored) { }
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
super.onDownloadDone(context, uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import android.content.Intent;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.utils.NotificationMgr;
|
import com.topjohnwu.magisk.utils.Notifications;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
|
|
||||||
@ -28,6 +28,6 @@ public class OnBootService extends JobIntentService {
|
|||||||
* to reboot if dtbo wasn't patched and patched by Magisk Manager.
|
* to reboot if dtbo wasn't patched and patched by Magisk Manager.
|
||||||
* */
|
* */
|
||||||
if (Shell.rootAccess() && ShellUtils.fastCmdResult("mm_patch_dtbo"))
|
if (Shell.rootAccess() && ShellUtils.fastCmdResult("mm_patch_dtbo"))
|
||||||
NotificationMgr.dtboPatched();
|
Notifications.dtboPatched();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
package com.topjohnwu.magisk.utils;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import com.androidnetworking.AndroidNetworking;
|
||||||
|
import com.androidnetworking.error.ANError;
|
||||||
|
import com.androidnetworking.interfaces.DownloadListener;
|
||||||
|
import com.topjohnwu.magisk.Const;
|
||||||
|
import com.topjohnwu.magisk.Data;
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
||||||
|
import com.topjohnwu.magisk.components.NotificationProgress;
|
||||||
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
|
import com.topjohnwu.utils.JarMap;
|
||||||
|
import com.topjohnwu.utils.SignAPK;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
|
public class DlInstallManager {
|
||||||
|
|
||||||
|
public static void upgrade(String name) {
|
||||||
|
dlInstall(name, new PatchPackageName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void restore() {
|
||||||
|
String name = Utils.fmt("MagiskManager v%s(%d)",
|
||||||
|
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
||||||
|
dlInstall(name, new RestoreManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void dlInstall(String name, ManagerDownloadListener listener) {
|
||||||
|
MagiskManager mm = Data.MM();
|
||||||
|
File apk = new File(mm.getFilesDir(), "manager.apk");
|
||||||
|
NotificationProgress progress = new NotificationProgress(name);
|
||||||
|
listener.setInstances(apk, progress);
|
||||||
|
AndroidNetworking
|
||||||
|
.download(Data.managerLink, apk.getParent(), apk.getName())
|
||||||
|
.setExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
|
||||||
|
.build()
|
||||||
|
.setDownloadProgressListener(progress)
|
||||||
|
.startDownload(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class ManagerDownloadListener implements DownloadListener {
|
||||||
|
private File apk;
|
||||||
|
private NotificationProgress progress;
|
||||||
|
|
||||||
|
private void setInstances(File apk, NotificationProgress progress) {
|
||||||
|
this.apk = apk;
|
||||||
|
this.progress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void onDownloadComplete(File apk, NotificationProgress progress);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onDownloadComplete() {
|
||||||
|
onDownloadComplete(apk, progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ANError anError) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PatchPackageName extends ManagerDownloadListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDownloadComplete(File apk, NotificationProgress progress) {
|
||||||
|
File patched = apk;
|
||||||
|
MagiskManager mm = Data.MM();
|
||||||
|
if (!mm.getPackageName().equals(Const.ORIG_PKG_NAME)) {
|
||||||
|
progress.getBuilder()
|
||||||
|
.setProgress(0, 0, true)
|
||||||
|
.setContentText("Patching APK");
|
||||||
|
progress.update();
|
||||||
|
patched = new File(apk.getParent(), "patched.apk");
|
||||||
|
try {
|
||||||
|
JarMap jarMap = new JarMap(apk);
|
||||||
|
PatchAPK.patchPackageID(jarMap, Const.ORIG_PKG_NAME, mm.getPackageName());
|
||||||
|
SignAPK.sign(jarMap, new BufferedOutputStream(new FileOutputStream(patched)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
progress.defaultDone();
|
||||||
|
APKInstall.install(mm, patched);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RestoreManager extends ManagerDownloadListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDownloadComplete(File apk, NotificationProgress progress) {
|
||||||
|
progress.defaultDone();
|
||||||
|
Data.exportPrefs();
|
||||||
|
if (ShellUtils.fastCmdResult("pm install " + apk))
|
||||||
|
RootUtils.rmAndLaunch(Data.MM().getPackageName(), Const.ORIG_PKG_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
package com.topjohnwu.magisk.utils;
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
@ -14,9 +12,10 @@ import com.topjohnwu.magisk.receivers.ManagerUpdate;
|
|||||||
import com.topjohnwu.magisk.receivers.RebootReceiver;
|
import com.topjohnwu.magisk.receivers.RebootReceiver;
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
import androidx.core.app.TaskStackBuilder;
|
import androidx.core.app.TaskStackBuilder;
|
||||||
|
|
||||||
public class NotificationMgr {
|
public class Notifications {
|
||||||
|
|
||||||
public static void magiskUpdate() {
|
public static void magiskUpdate() {
|
||||||
MagiskManager mm = Data.MM();
|
MagiskManager mm = Data.MM();
|
||||||
@ -37,19 +36,18 @@ public class NotificationMgr {
|
|||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setContentIntent(pendingIntent);
|
.setContentIntent(pendingIntent);
|
||||||
|
|
||||||
NotificationManager notificationManager =
|
NotificationManagerCompat mgr = NotificationManagerCompat.from(mm);
|
||||||
(NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE);
|
mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build());
|
||||||
notificationManager.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void managerUpdate() {
|
public static void managerUpdate() {
|
||||||
MagiskManager mm = Data.MM();
|
MagiskManager mm = Data.MM();
|
||||||
String filename = Utils.fmt("MagiskManager-v%s(%d).apk",
|
String name = Utils.fmt("MagiskManager v%s(%d)",
|
||||||
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
||||||
|
|
||||||
Intent intent = new Intent(mm, Data.classMap.get(ManagerUpdate.class));
|
Intent intent = new Intent(mm, Data.classMap.get(ManagerUpdate.class));
|
||||||
intent.putExtra(Const.Key.INTENT_SET_LINK, Data.managerLink);
|
intent.putExtra(Const.Key.INTENT_SET_LINK, Data.managerLink);
|
||||||
intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename);
|
intent.putExtra(Const.Key.INTENT_SET_NAME, name);
|
||||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(mm,
|
PendingIntent pendingIntent = PendingIntent.getBroadcast(mm,
|
||||||
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
@ -61,9 +59,8 @@ public class NotificationMgr {
|
|||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setContentIntent(pendingIntent);
|
.setContentIntent(pendingIntent);
|
||||||
|
|
||||||
NotificationManager notificationManager =
|
NotificationManagerCompat mgr = NotificationManagerCompat.from(mm);
|
||||||
(NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE);
|
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build());
|
||||||
notificationManager.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void dtboPatched() {
|
public static void dtboPatched() {
|
||||||
@ -80,8 +77,16 @@ public class NotificationMgr {
|
|||||||
.setVibrate(new long[]{0, 100, 100, 100})
|
.setVibrate(new long[]{0, 100, 100, 100})
|
||||||
.addAction(R.drawable.ic_refresh, mm.getString(R.string.reboot), pendingIntent);
|
.addAction(R.drawable.ic_refresh, mm.getString(R.string.reboot), pendingIntent);
|
||||||
|
|
||||||
NotificationManager notificationManager =
|
NotificationManagerCompat mgr = NotificationManagerCompat.from(mm);
|
||||||
(NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE);
|
mgr.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build());
|
||||||
notificationManager.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build());
|
}
|
||||||
|
|
||||||
|
public static NotificationCompat.Builder progress(String title) {
|
||||||
|
MagiskManager mm = Data.MM();
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL);
|
||||||
|
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setProgress(0, 0, true);
|
||||||
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,6 +16,7 @@ import android.os.AsyncTask;
|
|||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.androidnetworking.AndroidNetworking;
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
@ -150,4 +151,9 @@ public class Utils {
|
|||||||
return Shell.rootAccess() && (Const.USER_ID == 0 ||
|
return Shell.rootAccess() && (Const.USER_ID == 0 ||
|
||||||
Data.multiuserState != Const.Value.MULTIUSER_MODE_OWNER_MANAGED);
|
Data.multiuserState != Const.Value.MULTIUSER_MODE_OWNER_MANAGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String dlString(String url) {
|
||||||
|
String s = (String) AndroidNetworking.get(url).build().executeForString().getResult();
|
||||||
|
return s == null ? "" : s;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,75 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.components;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
|
|
||||||
public abstract class BaseActivity extends FlavorActivity {
|
|
||||||
|
|
||||||
public static final String INTENT_PERM = "perm_dialog";
|
|
||||||
|
|
||||||
protected static Runnable permissionGrantCallback;
|
|
||||||
|
|
||||||
public static void runWithPermission(Context context, String[] permissions, Runnable callback) {
|
|
||||||
boolean granted = true;
|
|
||||||
for (String perm : permissions) {
|
|
||||||
if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED)
|
|
||||||
granted = false;
|
|
||||||
}
|
|
||||||
if (granted) {
|
|
||||||
Download.EXTERNAL_PATH.mkdirs();
|
|
||||||
callback.run();
|
|
||||||
} else {
|
|
||||||
// Passed in context should be an activity if not granted, need to show dialog!
|
|
||||||
permissionGrantCallback = callback;
|
|
||||||
if (!(context instanceof BaseActivity)) {
|
|
||||||
// Start activity to show dialog
|
|
||||||
Intent intent = new Intent(context, a.g.class);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
intent.putExtra(INTENT_PERM, permissions);
|
|
||||||
context.startActivity(intent);
|
|
||||||
} else {
|
|
||||||
ActivityCompat.requestPermissions((BaseActivity) context, permissions, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void runWithPermission(String[] permissions, Runnable callback) {
|
|
||||||
runWithPermission(this, permissions, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
String[] perms = getIntent().getStringArrayExtra(INTENT_PERM);
|
|
||||||
if (perms != null)
|
|
||||||
ActivityCompat.requestPermissions(this, perms, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
||||||
boolean grant = true;
|
|
||||||
for (int result : grantResults) {
|
|
||||||
if (result != PackageManager.PERMISSION_GRANTED)
|
|
||||||
grant = false;
|
|
||||||
}
|
|
||||||
if (grant) {
|
|
||||||
if (permissionGrantCallback != null) {
|
|
||||||
permissionGrantCallback.run();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Toast.makeText(this, R.string.no_rw_storage, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
permissionGrantCallback = null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.receivers;
|
|
||||||
|
|
||||||
import android.app.DownloadManager;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public abstract class DownloadReceiver extends BroadcastReceiver {
|
|
||||||
protected File mFile;
|
|
||||||
private long downloadID;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
String action = intent.getAction();
|
|
||||||
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
query.setFilterById(downloadID);
|
|
||||||
Cursor c = downloadManager.query(query);
|
|
||||||
if (c.moveToFirst()) {
|
|
||||||
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
|
|
||||||
int status = c.getInt(columnIndex);
|
|
||||||
switch (status) {
|
|
||||||
case DownloadManager.STATUS_SUCCESSFUL:
|
|
||||||
Uri uri = Uri.parse(c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)));
|
|
||||||
onDownloadDone(context, uri);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Toast.makeText(context, R.string.download_file_error, Toast.LENGTH_LONG).show();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
context.unregisterReceiver(this);
|
|
||||||
}
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
Download.isDownloading = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DownloadReceiver setDownloadID(long id) {
|
|
||||||
downloadID = id;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DownloadReceiver setFile(File file) {
|
|
||||||
mFile = file;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void onDownloadDone(Context context, Uri uri);
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.receivers;
|
package com.topjohnwu.magisk.utils;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@ -9,22 +9,20 @@ import java.io.File;
|
|||||||
|
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
|
|
||||||
public class ManagerInstall extends DownloadReceiver {
|
public class APKInstall {
|
||||||
@Override
|
public static void install(Context c, File apk) {
|
||||||
public void onDownloadDone(Context context, Uri uri) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE);
|
Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE);
|
||||||
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
Uri content = FileProvider.getUriForFile(context,
|
Uri content = FileProvider.getUriForFile(c, c.getPackageName() + ".provider", apk);
|
||||||
context.getPackageName() + ".provider", new File(uri.getPath()));
|
|
||||||
install.setData(content);
|
install.setData(content);
|
||||||
context.startActivity(install);
|
c.startActivity(install);
|
||||||
} else {
|
} else {
|
||||||
Intent install = new Intent(Intent.ACTION_VIEW);
|
Intent install = new Intent(Intent.ACTION_VIEW);
|
||||||
install.setDataAndType(uri, "application/vnd.android.package-archive");
|
install.setDataAndType(Uri.fromFile(apk), "application/vnd.android.package-archive");
|
||||||
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
context.startActivity(install);
|
c.startActivity(install);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,9 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
package com.topjohnwu.magisk.utils;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.DownloadManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
import com.topjohnwu.magisk.components.BaseActivity;
|
|
||||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
@ -25,33 +16,6 @@ public class Download {
|
|||||||
EXTERNAL_PATH.mkdirs();
|
EXTERNAL_PATH.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isDownloading = false;
|
|
||||||
|
|
||||||
public static void receive(Context context, DownloadReceiver receiver, String link, String filename) {
|
|
||||||
if (isDownloading)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BaseActivity.runWithPermission(context,
|
|
||||||
new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, () -> {
|
|
||||||
File file = new File(EXTERNAL_PATH, getLegalFilename(filename));
|
|
||||||
file.delete();
|
|
||||||
|
|
||||||
Toast.makeText(context, context.getString(R.string.downloading_toast, filename),
|
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
|
|
||||||
isDownloading = true;
|
|
||||||
|
|
||||||
DownloadManager.Request request = new DownloadManager
|
|
||||||
.Request(Uri.parse(link))
|
|
||||||
.setDestinationUri(Uri.fromFile(file));
|
|
||||||
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
receiver.setDownloadID(dm.enqueue(request)).setFile(file);
|
|
||||||
context.getApplicationContext().registerReceiver(receiver,
|
|
||||||
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getLegalFilename(CharSequence filename) {
|
public static String getLegalFilename(CharSequence filename) {
|
||||||
return filename.toString().replace(" ", "_").replace("'", "").replace("\"", "")
|
return filename.toString().replace(" ", "_").replace("'", "").replace("\"", "")
|
||||||
.replace("$", "").replace("`", "").replace("*", "").replace("/", "_")
|
.replace("$", "").replace("`", "").replace("*", "").replace("/", "_")
|
||||||
|
@ -1,79 +1,24 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
package com.topjohnwu.magisk.utils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class WebService {
|
public class WebService {
|
||||||
|
|
||||||
public static String getString(String url) {
|
public static HttpURLConnection request(String address) throws IOException {
|
||||||
return getString(url, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getString(String url, Map<String, String> header) {
|
|
||||||
try {
|
|
||||||
HttpURLConnection conn = request(url, header);
|
|
||||||
return getString(conn);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getString(HttpURLConnection conn) {
|
|
||||||
try {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
|
|
||||||
int len;
|
|
||||||
char buf[] = new char[4096];
|
|
||||||
while ((len = br.read(buf)) != -1) {
|
|
||||||
builder.append(buf, 0, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
conn.disconnect();
|
|
||||||
return builder.toString();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HttpURLConnection request(String address, Map<String, String> header) throws IOException {
|
|
||||||
URL url = new URL(address);
|
URL url = new URL(address);
|
||||||
|
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
conn.setReadTimeout(15000);
|
conn.setReadTimeout(15000);
|
||||||
conn.setConnectTimeout(15000);
|
conn.setConnectTimeout(15000);
|
||||||
|
|
||||||
if (header != null) {
|
|
||||||
for (Map.Entry<String, String> entry : header.entrySet()) {
|
|
||||||
conn.setRequestProperty(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.connect();
|
conn.connect();
|
||||||
|
|
||||||
if (header != null) {
|
|
||||||
header.clear();
|
|
||||||
for (Map.Entry<String, List<String>> entry : conn.getHeaderFields().entrySet()) {
|
|
||||||
List<String> l = entry.getValue();
|
|
||||||
header.put(entry.getKey(), l.get(l.size() - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HttpURLConnection mustRequest(String address, Map<String, String> header) throws IOException {
|
public static HttpURLConnection mustRequest(String address) throws IOException {
|
||||||
HttpURLConnection conn;
|
HttpURLConnection conn;
|
||||||
do {
|
do {
|
||||||
conn = WebService.request(address, header);
|
conn = WebService.request(address);
|
||||||
int total = conn.getContentLength();
|
int total = conn.getContentLength();
|
||||||
if (total < 0)
|
if (total < 0)
|
||||||
conn.disconnect();
|
conn.disconnect();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<paths>
|
<paths>
|
||||||
|
<files-path name="internal_files" path="."/>
|
||||||
<external-path name="external_files" path="."/>
|
<external-path name="external_files" path="."/>
|
||||||
</paths>
|
</paths>
|
@ -1,10 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="com.topjohnwu.magisk">
|
package="com.topjohnwu.magisk">
|
||||||
|
|
||||||
<application>
|
<application
|
||||||
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
<activity
|
<activity
|
||||||
android:name=".NoUIActivity"
|
android:label="@string/app_name"
|
||||||
|
android:name=".MainActivity"
|
||||||
android:theme="@android:style/Theme.Translucent.NoTitleBar">
|
android:theme="@android:style/Theme.Translucent.NoTitleBar">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@ -12,7 +15,7 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<receiver android:name=".receivers.BootLauncher">
|
<receiver android:name=".BootLauncher">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
package com.topjohnwu.magisk.receivers;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.NoUIActivity;
|
|
||||||
|
|
||||||
public class BootLauncher extends BroadcastReceiver {
|
public class BootLauncher extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (TextUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED)) {
|
if (TextUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED)) {
|
||||||
Intent i = new Intent(context, NoUIActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
Intent i = new Intent(context, MainActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
context.startActivity(i);
|
context.startActivity(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
105
app/src/stub/java/com/topjohnwu/magisk/MainActivity.java
Normal file
105
app/src/stub/java/com/topjohnwu/magisk/MainActivity.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Application;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.utils.APKInstall;
|
||||||
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
|
import com.topjohnwu.magisk.utils.WebService;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
public class MainActivity extends Activity {
|
||||||
|
|
||||||
|
private static final String URL =
|
||||||
|
"https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json";
|
||||||
|
|
||||||
|
private String apkLink;
|
||||||
|
|
||||||
|
private void dlAPK() {
|
||||||
|
Application app = getApplication();
|
||||||
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
|
try {
|
||||||
|
HttpURLConnection conn = WebService.request(apkLink);
|
||||||
|
File apk = new File(getFilesDir(), "manager.apk");
|
||||||
|
try (InputStream in = new BufferedInputStream(conn.getInputStream());
|
||||||
|
OutputStream out = new BufferedOutputStream(new FileOutputStream(apk))) {
|
||||||
|
int len;
|
||||||
|
byte[] buf = new byte[4096];
|
||||||
|
while ((len = in.read(buf)) != -1) {
|
||||||
|
out.write(buf, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.disconnect();
|
||||||
|
APKInstall.install(app, apk);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dlJSON() throws IOException, JSONException {
|
||||||
|
HttpURLConnection conn = WebService.request(URL);
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
|
||||||
|
int len;
|
||||||
|
char buf[] = new char[4096];
|
||||||
|
while ((len = br.read(buf)) != -1) {
|
||||||
|
builder.append(buf, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.disconnect();
|
||||||
|
JSONObject json = new JSONObject(builder.toString());
|
||||||
|
JSONObject manager = json.getJSONObject("app");
|
||||||
|
apkLink = manager.getString("link");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
if (Download.checkNetworkStatus(this)) {
|
||||||
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
|
try {
|
||||||
|
dlJSON();
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setTitle(R.string.app_name)
|
||||||
|
.setMessage(R.string.upgrade_msg)
|
||||||
|
.setPositiveButton(R.string.yes, (d, w) -> dlAPK())
|
||||||
|
.setNegativeButton(R.string.no_thanks, (d, w) -> finish())
|
||||||
|
.show();
|
||||||
|
});
|
||||||
|
} catch (JSONException | IOException e) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setTitle(R.string.app_name)
|
||||||
|
.setMessage(R.string.no_internet_msg)
|
||||||
|
.setNegativeButton(R.string.ok, (d, w) -> finish())
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,70 +0,0 @@
|
|||||||
package com.topjohnwu.magisk;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.components.BaseActivity;
|
|
||||||
import com.topjohnwu.magisk.receivers.ManagerInstall;
|
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public class NoUIActivity extends BaseActivity {
|
|
||||||
|
|
||||||
private String apkLink;
|
|
||||||
private String version;
|
|
||||||
private int versionCode;
|
|
||||||
|
|
||||||
public static final String URL =
|
|
||||||
"https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
if (Download.checkNetworkStatus(this)) {
|
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
|
||||||
String str = WebService.getString(URL);
|
|
||||||
try {
|
|
||||||
JSONObject json = new JSONObject(str);
|
|
||||||
JSONObject manager = json.getJSONObject("app");
|
|
||||||
version = manager.getString("version");
|
|
||||||
versionCode = manager.getInt("versionCode");
|
|
||||||
apkLink = manager.getString("link");
|
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
runOnUiThread(() -> {
|
|
||||||
String filename = String.format(Locale.US, "MagiskManager-v%s(%d).apk",
|
|
||||||
version, versionCode);
|
|
||||||
new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT)
|
|
||||||
.setCancelable(false)
|
|
||||||
.setTitle(R.string.app_name)
|
|
||||||
.setMessage(R.string.upgrade_msg)
|
|
||||||
.setPositiveButton(R.string.yes, (d, w) -> runWithPermission(new String[]
|
|
||||||
{ Manifest.permission.WRITE_EXTERNAL_STORAGE }, () -> {
|
|
||||||
Download.receive(this, new ManagerInstall(), apkLink, filename);
|
|
||||||
finish();
|
|
||||||
}))
|
|
||||||
.setNegativeButton(R.string.no_thanks, (d, w) -> finish())
|
|
||||||
.show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT)
|
|
||||||
.setCancelable(false)
|
|
||||||
.setTitle(R.string.app_name)
|
|
||||||
.setMessage(R.string.no_internet_msg)
|
|
||||||
.setNegativeButton(R.string.ok, (d, w) -> finish())
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.components;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
|
|
||||||
public abstract class FlavorActivity extends Activity {}
|
|
Loading…
x
Reference in New Issue
Block a user