diff --git a/app/build.gradle b/app/build.gradle index f0fe1579d..f79b80a36 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -32,10 +32,11 @@ repositories { dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:recyclerview-v7:24.2.0' - compile 'com.android.support:cardview-v7:24.2.0' - compile 'com.android.support:design:24.2.0' + compile 'com.android.support:recyclerview-v7:24.2.1' + compile 'com.android.support:cardview-v7:24.2.1' + compile 'com.android.support:design:24.2.1' compile 'com.jakewharton:butterknife:8.4.0' compile 'com.github.michalis-vitos:aFileChooser:master' + compile 'com.google.code.gson:gson:2.7' annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' } diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java index 817b39714..623e25b0b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java @@ -7,7 +7,6 @@ import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.content.FileProvider; import android.support.v7.app.AlertDialog; -import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,6 +14,7 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Utils; import java.io.File; @@ -112,7 +112,7 @@ public class MagiskFragment extends Fragment { new Utils.DownloadReceiver(getString(R.string.magisk)) { @Override public void task(File file) { - new Utils.FlashZIP(mContext, mName, file.getPath()).execute(); + new Async.FlashZIP(mContext, mName, file.getPath()).execute(); } }, Utils.magiskLink, "latest_magisk.zip"); diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java index 36085bf09..dd781c065 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java @@ -21,6 +21,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import com.topjohnwu.magisk.module.Module; +import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebWindow; @@ -109,7 +110,7 @@ public class ModulesAdapter extends RecyclerView.Adapter { recyclerView.setVisibility(View.GONE); - new Utils.LoadModules(getActivity()).execute(); + new Async.LoadModules(getActivity()).execute(); new updateUI().execute(); prefs.edit().putBoolean("ignoreUpdateAlerts", false).apply(); diff --git a/app/src/main/java/com/topjohnwu/magisk/QuickSettingTileService.java b/app/src/main/java/com/topjohnwu/magisk/QuickSettingTileService.java index 02b820412..f6ab65254 100644 --- a/app/src/main/java/com/topjohnwu/magisk/QuickSettingTileService.java +++ b/app/src/main/java/com/topjohnwu/magisk/QuickSettingTileService.java @@ -32,7 +32,7 @@ public class QuickSettingTileService extends TileService { Icon iconAuto = Icon.createWithResource(getApplicationContext(), R.drawable.ic_autoroot); Tile tile = this.getQsTile(); boolean autoRootStatus = Utils.autoRootEnabled(getApplicationContext()); - boolean rootStatus = Utils.rootStatus(); + boolean rootStatus = Utils.rootEnabled(); Log.d("Magisk", "QST: Auto and root are " + autoRootStatus + " and " + rootStatus); if (autoRootStatus) { tile.setLabel("Auto-root"); diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java index b9b86ca78..7eadd1db7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -21,6 +21,7 @@ import android.widget.TextView; import android.widget.Toast; import com.topjohnwu.magisk.module.Repo; +import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebWindow; @@ -150,7 +151,7 @@ public class ReposAdapter extends RecyclerView.Adapter @Override public void task(File file) { Log.d("Magisk", "Task firing"); - new Utils.FlashZIP(context, repo.getId(), file.toString()).execute(); + new Async.FlashZIP(context, repo.getId(), file.toString()).execute(); } }; String filename = repo.getId().replace(" ", "") + ".zip"; diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java index 0342c2dc4..69edc410f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -17,6 +17,7 @@ import android.widget.TextView; import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.module.RepoHelper; +import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Utils; import java.io.File; @@ -133,7 +134,7 @@ public class ReposFragment extends Fragment { @Override public void task(File file) { Log.d("Magisk", "Task firing"); - new Utils.FlashZIP(getActivity(), repo.getId(), file.toString()).execute(); + new Async.FlashZIP(getActivity(), repo.getId(), file.toString()).execute(); } }; String filename = repo.getId().replace(" ", "") + ".zip"; diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java index e2da03e0a..7254a660f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java @@ -24,6 +24,7 @@ import android.view.MenuItem; import android.view.View; import com.topjohnwu.magisk.module.RepoHelper; +import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Utils; import butterknife.BindView; @@ -72,16 +73,16 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView } - new Utils.Initialize(this).execute(); - new Utils.CheckUpdates(this).execute(); + Utils.init(this); + new Async.CheckUpdates(this).execute(); RepoHelper.TaskDelegate delegate = result -> { //Do a thing here when we get a result we want }; - new Utils.LoadModules(this).execute(); - new Utils.LoadRepos(this, true, delegate).execute(); - new Utils.LoadRepos(this, !prefs.contains("hasCachedRepos"), delegate).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - new Utils.LoadModules(getApplication()).execute(); - new Utils.LoadRepos(this, false, delegate).execute(); + new Async.LoadModules(this).execute(); + new Async.LoadRepos(this, true, delegate).execute(); + new Async.LoadRepos(this, !prefs.contains("hasCachedRepos"), delegate).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new Async.LoadModules(getApplication()).execute(); + new Async.LoadRepos(this, false, delegate).execute(); setSupportActionBar(toolbar); diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Async.java b/app/src/main/java/com/topjohnwu/magisk/utils/Async.java new file mode 100644 index 000000000..ca100fcbe --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Async.java @@ -0,0 +1,379 @@ +package com.topjohnwu.magisk.utils; + +import android.app.ProgressDialog; +import android.content.ContentResolver; +import android.content.Context; +import android.net.Uri; +import android.os.AsyncTask; +import android.provider.DocumentsContract; +import android.support.v7.app.AlertDialog; +import android.util.Log; +import android.widget.Toast; + +import com.topjohnwu.magisk.ModulesFragment; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.ReposFragment; +import com.topjohnwu.magisk.module.Module; +import com.topjohnwu.magisk.module.Repo; +import com.topjohnwu.magisk.module.RepoHelper; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.List; + +public class Async { + + public static class CheckUpdates extends AsyncTask { + + private Context mContext; + + public CheckUpdates(Context context) { + mContext = context; + } + + @Override + protected Void doInBackground(Void... voids) { + try { + HttpURLConnection c = (HttpURLConnection) new URL(Utils.UPDATE_JSON).openConnection(); + c.setRequestMethod("GET"); + c.setInstanceFollowRedirects(false); + c.setDoOutput(false); + c.connect(); + + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + } + br.close(); + JSONObject json = new JSONObject(sb.toString()); + JSONObject magisk = json.getJSONObject("magisk"); + JSONObject app = json.getJSONObject("app"); + JSONObject root = json.getJSONObject("root"); + + Utils.remoteMagiskVersion = magisk.getInt("versionCode"); + Utils.magiskLink = magisk.getString("link"); + Utils.magiskChangelog = magisk.getString("changelog"); + + Utils.remoteAppVersion = app.getInt("versionCode"); + Utils.appLink = app.getString("link"); + Utils.appChangelog = app.getString("changelog"); + + Utils.phhLink = root.getString("phh"); + Utils.supersuLink = root.getString("supersu"); + + } catch (IOException | JSONException ignored) { + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + if (Shell.rootAccess() && Utils.magiskVersion == -1) { + new AlertDialog.Builder(mContext) + .setTitle(R.string.no_magisk_title) + .setMessage(R.string.no_magisk_msg) + .setCancelable(true) + .setPositiveButton(R.string.download_install, (dialogInterface, i) -> { + new AlertDialog.Builder(mContext) + .setTitle(R.string.root_method_title) + .setItems(new String[]{mContext.getString(R.string.phh), mContext.getString(R.string.supersu)}, (dialogInterface1, root) -> { + Utils.DownloadReceiver rootReceiver; + String link, filename; + switch (root) { + case 0: + link = Utils.phhLink; + filename = "phhsu.zip"; + rootReceiver = new Utils.DownloadReceiver(mContext.getString(R.string.phh)) { + @Override + public void task(File file) { + new FlashZIP(mContext, mName, file.getPath()).execute(); + } + }; + break; + case 1: + link = Utils.supersuLink; + filename = "supersu.zip"; + rootReceiver = new Utils.DownloadReceiver(mContext.getString(R.string.supersu)) { + @Override + public void task(File file) { + new FlashZIP(mContext, mName, file.getPath()).execute(); + } + }; + break; + default: + rootReceiver = null; + link = filename = null; + } + Utils.DownloadReceiver magiskReceiver = new Utils.DownloadReceiver(mContext.getString(R.string.magisk)) { + @Override + public void task(File file) { + Context temp = mContext; + new FlashZIP(mContext, mName, file.getPath()) { + @Override + protected void done() { + Utils.downloadAndReceive(temp, rootReceiver, link, filename); + } + }.execute(); + } + }; + Utils.downloadAndReceive(mContext, magiskReceiver, Utils.magiskLink, "latest_magisk.zip"); + }) + .show(); + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } else if (Shell.rootStatus == 2) { + new AlertDialog.Builder(mContext) + .setTitle(R.string.root_system) + .setMessage(R.string.root_system_msg) + .setCancelable(true) + .setPositiveButton(R.string.download_install, (dialogInterface, i) -> { + new AlertDialog.Builder(mContext) + .setTitle(R.string.root_method_title) + .setItems(new String[]{mContext.getString(R.string.phh), mContext.getString(R.string.supersu)}, (dialogInterface1, root) -> { + switch (root) { + case 0: + Utils.downloadAndReceive( + mContext, + new Utils.DownloadReceiver(mContext.getString(R.string.phh)) { + @Override + public void task(File file) { + new FlashZIP(mContext, mName, file.getPath()).execute(); + } + }, + Utils.phhLink, "phhsu.zip"); + break; + case 1: + Utils.downloadAndReceive( + mContext, + new Utils.DownloadReceiver(mContext.getString(R.string.supersu)) { + @Override + public void task(File file) { + new FlashZIP(mContext, mName, file.getPath()).execute(); + } + }, + Utils.supersuLink, "supersu.zip"); + break; + } + }) + .show(); + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } + } + } + + public static class LoadModules extends AsyncTask { + + private Context mContext; + + public LoadModules(Context context) { + mContext = context; + } + + @Override + protected Void doInBackground(Void... voids) { + ModulesFragment.listModules.clear(); + List magisk = Utils.getModList(Utils.MAGISK_PATH); + Log.d("Magisk", "Utils: Reload called, loading modules"); + List magiskCache = Utils.getModList(Utils.MAGISK_CACHE_PATH); + + for (String mod : magisk) { + Log.d("Magisk", "Utils: Adding module from string " + mod); + ModulesFragment.listModules.add(new Module(mod, mContext)); + } + + for (String mod : magiskCache) { + Log.d("Magisk", "Utils: Adding cache module from string " + mod); + Module cacheMod = new Module(mod, mContext); + // Prevent people forgot to change module.prop + cacheMod.setCache(); + ModulesFragment.listModules.add(cacheMod); + } + + return null; + } + + } + + public static class LoadRepos extends AsyncTask { + + private Context mContext; + private boolean doReload; + private RepoHelper.TaskDelegate mTaskDelegate; + + public LoadRepos(Context context, boolean reload, RepoHelper.TaskDelegate delegate) { + mContext = context; + doReload = reload; + mTaskDelegate = delegate; + } + + @Override + protected Void doInBackground(Void... voids) { + ReposFragment.mListRepos.clear(); + List magiskRepos = RepoHelper.listRepos(mContext, doReload, mTaskDelegate); + + for (Repo repo : magiskRepos) { + Log.d("Magisk", "Utils: Adding repo from string " + repo.getId()); + ReposFragment.mListRepos.add(repo); + } + + return null; + } + + } + + public static class FlashZIP extends AsyncTask { + + private String mPath, mName; + private Uri mUri; + private ProgressDialog progress; + private File mFile; + private Context mContext; + private List ret; + private boolean deleteFileAfter; + + public FlashZIP(Context context, String name, String path) { + mContext = context; + mName = name; + mPath = path; + deleteFileAfter = false; + } + + public FlashZIP(Context context, Uri uRi) { + mContext = context; + mUri = uRi; + deleteFileAfter = true; + String file = ""; + final String docId = DocumentsContract.getDocumentId(mUri); + + Log.d("Magisk", "Utils: FlashZip Running, " + docId + " and " + mUri.toString()); + if (docId.contains(":")) + mName = docId.split(":")[1]; + else mName = docId; + if (mName.contains("/")) + mName = mName.substring(mName.lastIndexOf('/') + 1); + if (mName.contains(".zip")) { + file = mContext.getFilesDir() + "/" + mName; + Log.d("Magisk", "Utils: FlashZip running for uRI " + mUri.toString()); + } else { + Log.e("Magisk", "Utils: error parsing Zipfile " + mUri.getPath()); + this.cancel(true); + } + ContentResolver contentResolver = mContext.getContentResolver(); + //contentResolver.takePersistableUriPermission(mUri, flags); + try { + InputStream in = contentResolver.openInputStream(mUri); + Log.d("Magisk", "Firing inputStream"); + mFile = createFileFromInputStream(in, file, mContext); + if (mFile != null) { + mPath = mFile.getPath(); + Log.d("Magisk", "Utils: Mpath is " + mPath); + } else { + Log.e("Magisk", "Utils: error creating file " + mUri.getPath()); + this.cancel(true); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + // TODO handle non-primary volumes + + } + + private static File createFileFromInputStream(InputStream inputStream, String fileName, Context context) { + + try { + File f = new File(fileName); + f.setWritable(true, false); + OutputStream outputStream = new FileOutputStream(f); + byte buffer[] = new byte[1024]; + int length; + + while ((length = inputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + + outputStream.close(); + inputStream.close(); + Log.d("Magisk", "Holy balls, I think it worked. File is " + f.getPath()); + return f; + + } catch (IOException e) { + System.out.println("error in creating a file"); + e.printStackTrace(); + } + + return null; + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + + progress = ProgressDialog.show(mContext, mContext.getString(R.string.zip_install_progress_title), mContext.getString(R.string.zip_install_progress_msg, mName)); + } + + @Override + protected Boolean doInBackground(Void... voids) { + if (mPath != null) { + Log.e("Magisk", "Utils: Error, flashZIP called without a valid zip file to flash."); + progress.dismiss(); + this.cancel(true); + return false; + } + if (!Shell.rootAccess()) { + return false; + } else { + ret = Shell.su( + "rm -rf /dev/tmp", + "mkdir -p /dev/tmp", + "cp -af " + mPath + " /dev/tmp/install.zip", + "unzip -o /dev/tmp/install.zip META-INF/com/google/android/* -d /dev/tmp", + "BOOTMODE=true sh /dev/tmp/META-INF/com/google/android/update-binary dummy 1 /dev/tmp/install.zip", + "if [ $? -eq 0 ]; then echo true; else echo false; fi" + ); + return ret != null && Boolean.parseBoolean(ret.get(ret.size() - 1)); + } + } + + @Override + protected void onPostExecute(Boolean result) { + super.onPostExecute(result); + if (deleteFileAfter) { + Shell.su("rm -rf " + mPath); + Log.d("Magisk", "Utils: Deleting file " + mPath); + } + progress.dismiss(); + if (!result) { + Toast.makeText(mContext, mContext.getString(R.string.manual_install, mPath), Toast.LENGTH_LONG).show(); + return; + } + done(); + } + + protected void done() { + new AlertDialog.Builder(mContext) + .setTitle(R.string.reboot_title) + .setMessage(R.string.reboot_msg) + .setPositiveButton(R.string.reboot, (dialogInterface1, i) -> Shell.su("reboot")) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java index 2fba7801d..e2faeb93b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -72,6 +72,18 @@ public class Utils { public static final String MAGISK_CACHE_PATH = "/cache/magisk"; public static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json"; + public static void init(Context context) { + List ret = Shell.sh("getprop magisk.version"); + if (ret.get(0).replaceAll("\\s", "").isEmpty()) { + magiskVersion = -1; + } else { + magiskVersion = Integer.parseInt(ret.get(0)); + } + if (!Shell.rootAccess()) { + Snackbar.make(((Activity) context).findViewById(android.R.id.content), R.string.no_root_access, Snackbar.LENGTH_LONG).show(); + } + } + public static boolean fileExist(String path) { List ret; String command = "if [ -f " + path + " ]; then echo true; else echo false; fi"; @@ -134,17 +146,23 @@ public class Utils { public static List getModList(String path) { List ret; - ret = Shell.sh("find " + path + " -type d -maxdepth 1 ! -name \"*.core\" ! -name \"*lost+found\" ! -name \"*magisk\""); - if (ret.isEmpty() && Shell.rootAccess()) - ret = Shell.su("find " + path + " -type d -maxdepth 1 ! -name \"*.core\" ! -name \"*lost+found\" ! -name \"*magisk\""); + String command = "find " + path + " -type d -maxdepth 1 ! -name \"*.core\" ! -name \"*lost+found\" ! -name \"*magisk\""; + if (Shell.rootAccess()) { + ret = Shell.su(command); + } else { + ret = Shell.sh(command); + } return ret; } public static List readFile(String path) { List ret; - ret = Shell.sh("cat " + path); - if (ret.isEmpty() && Shell.rootAccess()) - ret = Shell.su("cat " + path); + String command = "cat " + path; + if (Shell.rootAccess()) { + ret = Shell.su(command); + } else { + ret = Shell.sh(command); + } return ret; } @@ -270,241 +288,6 @@ public class Utils { public abstract void task(File file); } - public static class Initialize extends AsyncTask { - - private Context mContext; - - public Initialize(Context context) { - mContext = context; - } - - @Override - protected Void doInBackground(Void... voids) { - List ret = Shell.sh("getprop magisk.version"); - if (ret.get(0).replaceAll("\\s", "").isEmpty()) { - magiskVersion = -1; - } else { - magiskVersion = Integer.parseInt(ret.get(0)); - } - - // Install Busybox and set as top priority -// if (Shell.rootAccess()) { -// String busybox = mContext.getApplicationInfo().nativeLibraryDir + "/libbusybox.so"; -// Shell.su( -// "rm -rf /data/busybox", -// "mkdir -p /data/busybox", -// "cp -af " + busybox + " /data/busybox/busybox", -// "chmod 755 /data/busybox /data/busybox/busybox", -// "chcon u:object_r:system_file:s0 /data/busybox /data/busybox/busybox", -// "/data/busybox/busybox --install -s /data/busybox", -// "rm -f /data/busybox/su", -// "export PATH=/data/busybox:$PATH" -// ); -// } - return null; - } - - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - if (!Shell.rootAccess()) { - Snackbar.make(((Activity) mContext).findViewById(android.R.id.content), R.string.no_root_access, Snackbar.LENGTH_LONG).show(); - } - - } - } - - public static class CheckUpdates extends AsyncTask { - - private Context mContext; - - public CheckUpdates(Context context) { - mContext = context; - } - - @Override - protected Void doInBackground(Void... voids) { - try { - HttpURLConnection c = (HttpURLConnection) new URL(UPDATE_JSON).openConnection(); - c.setRequestMethod("GET"); - c.setInstanceFollowRedirects(false); - c.setDoOutput(false); - c.connect(); - - BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = br.readLine()) != null) { - sb.append(line); - } - br.close(); - JSONObject json = new JSONObject(sb.toString()); - JSONObject magisk = json.getJSONObject("magisk"); - JSONObject app = json.getJSONObject("app"); - JSONObject root = json.getJSONObject("root"); - - remoteMagiskVersion = magisk.getInt("versionCode"); - magiskLink = magisk.getString("link"); - magiskChangelog = magisk.getString("changelog"); - - remoteAppVersion = app.getInt("versionCode"); - appLink = app.getString("link"); - appChangelog = app.getString("changelog"); - - phhLink = root.getString("phh"); - supersuLink = root.getString("supersu"); - - } catch (IOException | JSONException ignored) { - } - return null; - } - - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - if (Shell.rootAccess() && magiskVersion == -1) { - new AlertDialog.Builder(mContext) - .setTitle(R.string.no_magisk_title) - .setMessage(R.string.no_magisk_msg) - .setCancelable(true) - .setPositiveButton(R.string.download_install, (dialogInterface, i) -> { - new AlertDialog.Builder(mContext) - .setTitle(R.string.root_method_title) - .setItems(new String[]{mContext.getString(R.string.phh), mContext.getString(R.string.supersu)}, (dialogInterface1, root) -> { - DownloadReceiver rootReceiver; - String link, filename; - switch (root) { - case 0: - link = phhLink; - filename = "phhsu.zip"; - rootReceiver = new DownloadReceiver(mContext.getString(R.string.phh)) { - @Override - public void task(File file) { - new RemoveSystemSU().execute(); - new FlashZIP(mContext, mName, file.getPath()).execute(); - } - }; - break; - case 1: - link = supersuLink; - filename = "supersu.zip"; - rootReceiver = new DownloadReceiver(mContext.getString(R.string.supersu)) { - @Override - public void task(File file) { - new RemoveSystemSU().execute(); - new FlashZIP(mContext, mName, file.getPath()).execute(); - } - }; - break; - default: - rootReceiver = null; - link = filename = null; - } - DownloadReceiver magiskReceiver = new DownloadReceiver(mContext.getString(R.string.magisk)) { - @Override - public void task(File file) { - Context temp = mContext; - new FlashZIP(mContext, mName, file.getPath()) { - @Override - protected void done() { - downloadAndReceive(temp, rootReceiver, link, filename); - } - }.execute(); - } - }; - downloadAndReceive(mContext, magiskReceiver, magiskLink, "latest_magisk.zip"); - }) - .show(); - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } else if (Shell.rootStatus == 2) { - new AlertDialog.Builder(mContext) - .setTitle(R.string.root_system) - .setMessage(R.string.root_system_msg) - .setCancelable(true) - .setPositiveButton(R.string.download_install, (dialogInterface, i) -> { - new AlertDialog.Builder(mContext) - .setTitle(R.string.root_method_title) - .setItems(new String[]{mContext.getString(R.string.phh), mContext.getString(R.string.supersu)}, (dialogInterface1, root) -> { - switch (root) { - case 0: - downloadAndReceive( - mContext, - new DownloadReceiver(mContext.getString(R.string.phh)) { - @Override - public void task(File file) { - new FlashZIP(mContext, mName, file.getPath()).execute(); - } - }, - phhLink, "phhsu.zip"); - break; - case 1: - downloadAndReceive( - mContext, - new DownloadReceiver(mContext.getString(R.string.supersu)) { - @Override - public void task(File file) { - new FlashZIP(mContext, mName, file.getPath()).execute(); - } - }, - supersuLink, "supersu.zip"); - break; - } - }) - .show(); - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } - } - } - - public static class RemoveSystemSU extends AsyncTask { - - @Override - protected Void doInBackground(Void... voids) { - Shell.su( - "umount /system/xbin", - "umount -l /system/xbin", - "if [ ! -z $(which su | grep system) ]; then", - "mount -o rw,remount /system", - "rm -rf /system/.pin /system/app/SuperSU /system/bin/.ext /system/etc/.installed_su_daemon " + - "/system/etc/install-recovery.sh /system/etc/init.d/99SuperSUDaemon /system/xbin/daemonsu " + - "/system/xbin/su /system/xbin/sugote /system/xbin/sugote-mksh /system/xbin/supolicy " + - "/data/app/eu.chainfire.supersu-*", - "mv -f /system/bin/app_process32_original /system/bin/app_process32", - "mv -f /system/bin/app_process64_original /system/bin/app_process64", - "mv -f /system/bin/install-recovery_original.sh /system/bin/install-recovery.sh", - "if [ -e /system/bin/app_process64 ]; then", - "ln -sf /system/bin/app_process64 /system/bin/app_process", - "else", - "ln -sf /system/bin/app_process32 /system/bin/app_process", - "fi", - "umount /system", - "fi", - "setprop magisk.root 1" - ); - return null; - } - } - - public static boolean rootStatus() { - try { - String rootStatus = Shell.su("getprop magisk.root").toString(); - String fuckyeah = Shell.sh("which su").toString(); - Log.d("Magisk", "Utils: Rootstatus Checked, " + rootStatus + " and " + fuckyeah); - if (rootStatus.contains("0") && !fuckyeah.contains("su")) { - return false; - } else { - return true; - } - } catch (NullPointerException e) { - e.printStackTrace(); - return false; - } - } - public static boolean isMyServiceRunning(Class serviceClass, Context context) { ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { @@ -515,205 +298,6 @@ public class Utils { return false; } - public static class LoadModules extends AsyncTask { - - private Context mContext; - - public LoadModules(Context context) { - mContext = context; - } - - @Override - protected Void doInBackground(Void... voids) { - ModulesFragment.listModules.clear(); - List magisk = getModList(MAGISK_PATH); - Log.d("Magisk", "Utils: Reload called, loading modules"); - List magiskCache = getModList(MAGISK_CACHE_PATH); - - for (String mod : magisk) { - Log.d("Magisk", "Utils: Adding module from string " + mod); - ModulesFragment.listModules.add(new Module(mod, mContext)); - } - - for (String mod : magiskCache) { - Log.d("Magisk", "Utils: Adding cache module from string " + mod); - Module cacheMod = new Module(mod, mContext); - // Prevent people forgot to change module.prop - cacheMod.setCache(); - ModulesFragment.listModules.add(cacheMod); - } - - return null; - } - - } - - public static class LoadRepos extends AsyncTask { - - private Context mContext; - private boolean doReload; - private RepoHelper.TaskDelegate mTaskDelegate; - - public LoadRepos(Context context, boolean reload, RepoHelper.TaskDelegate delegate) { - mContext = context; - doReload = reload; - mTaskDelegate = delegate; - } - - @Override - protected Void doInBackground(Void... voids) { - ReposFragment.mListRepos.clear(); - List magiskRepos = RepoHelper.listRepos(mContext, doReload, mTaskDelegate); - - for (Repo repo : magiskRepos) { - Log.d("Magisk", "Utils: Adding repo from string " + repo.getId()); - ReposFragment.mListRepos.add(repo); - } - - return null; - } - - } - - public static class FlashZIP extends AsyncTask { - - private String mPath, mName; - private Uri mUri; - private ProgressDialog progress; - private File mFile; - private Context mContext; - private List ret; - private boolean deleteFileAfter; - - public FlashZIP(Context context, String name, String path) { - mContext = context; - mName = name; - mPath = path; - deleteFileAfter = false; - } - - public FlashZIP(Context context, Uri uRi) { - mContext = context; - mUri = uRi; - deleteFileAfter = true; - String file = ""; - final String docId = DocumentsContract.getDocumentId(mUri); - - Log.d("Magisk", "Utils: FlashZip Running, " + docId + " and " + mUri.toString()); - if (docId.contains(":")) - mName = docId.split(":")[1]; - else mName = docId; - if (mName.contains("/")) - mName = mName.substring(mName.lastIndexOf('/') + 1); - if (mName.contains(".zip")) { - file = mContext.getFilesDir() + "/" + mName; - Log.d("Magisk", "Utils: FlashZip running for uRI " + mUri.toString()); - } else { - Log.e("Magisk", "Utils: error parsing Zipfile " + mUri.getPath()); - this.cancel(true); - } - ContentResolver contentResolver = mContext.getContentResolver(); - //contentResolver.takePersistableUriPermission(mUri, flags); - try { - InputStream in = contentResolver.openInputStream(mUri); - Log.d("Magisk", "Firing inputStream"); - mFile = createFileFromInputStream(in, file, mContext); - if (mFile != null) { - mPath = mFile.getPath(); - Log.d("Magisk", "Utils: Mpath is " + mPath); - } else { - Log.e("Magisk", "Utils: error creating file " + mUri.getPath()); - this.cancel(true); - } - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - - // TODO handle non-primary volumes - - } - - private static File createFileFromInputStream(InputStream inputStream, String fileName, Context context) { - - try { - File f = new File(fileName); - f.setWritable(true, false); - OutputStream outputStream = new FileOutputStream(f); - byte buffer[] = new byte[1024]; - int length; - - while ((length = inputStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, length); - } - - outputStream.close(); - inputStream.close(); - Log.d("Magisk", "Holy balls, I think it worked. File is " + f.getPath()); - return f; - - } catch (IOException e) { - System.out.println("error in creating a file"); - e.printStackTrace(); - } - - return null; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - - progress = ProgressDialog.show(mContext, mContext.getString(R.string.zip_install_progress_title), mContext.getString(R.string.zip_install_progress_msg, mName)); - } - - @Override - protected Boolean doInBackground(Void... voids) { - if (mPath != null) { - Log.e("Magisk", "Utils: Error, flashZIP called without a valid zip file to flash."); - progress.dismiss(); - this.cancel(true); - return false; - } - if (!Shell.rootAccess()) { - return false; - } else { - ret = Shell.su( - "rm -rf /dev/tmp", - "mkdir -p /dev/tmp", - "cp -af " + mPath + " /dev/tmp/install.zip", - "unzip -o /dev/tmp/install.zip META-INF/com/google/android/* -d /dev/tmp", - "BOOTMODE=true sh /dev/tmp/META-INF/com/google/android/update-binary dummy 1 /dev/tmp/install.zip", - "if [ $? -eq 0 ]; then echo true; else echo false; fi" - ); - return ret != null && Boolean.parseBoolean(ret.get(ret.size() - 1)); - } - } - - @Override - protected void onPostExecute(Boolean result) { - super.onPostExecute(result); - if (deleteFileAfter) { - Shell.su("rm -rf " + mPath); - Log.d("Magisk", "Utils: Deleting file " + mPath); - } - progress.dismiss(); - if (!result) { - Toast.makeText(mContext, mContext.getString(R.string.manual_install, mPath), Toast.LENGTH_LONG).show(); - return; - } - done(); - } - - protected void done() { - new AlertDialog.Builder(mContext) - .setTitle(R.string.reboot_title) - .setMessage(R.string.reboot_msg) - .setPositiveButton(R.string.reboot, (dialogInterface1, i) -> Shell.su("reboot")) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } - } - public interface ItemClickListener { void onItemClick(View view, int position); diff --git a/build.gradle b/build.gradle index 24cf38d8a..1729a631c 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.0-rc1' + classpath 'com.android.tools.build:gradle:2.2.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files