diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java index a03c99240..b40192aa1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java @@ -27,6 +27,7 @@ import com.topjohnwu.magisk.components.ExpandableView; import com.topjohnwu.magisk.components.Fragment; import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.ShowUI; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; @@ -123,18 +124,18 @@ public class MagiskFragment extends Fragment // Show Manager update first if (mm.remoteManagerVersionCode > BuildConfig.VERSION_CODE) { - Utils.showManagerInstallDialog(getActivity()); + ShowUI.showManagerInstallDialog(getActivity()); return; } ((NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll(); - Utils.showMagiskInstallDialog(this, + ShowUI.showMagiskInstallDialog(this, keepEncChkbox.isChecked(), keepVerityChkbox.isChecked()); } @OnClick(R.id.uninstall_button) void uninstall() { - Utils.showUninstallDialog(this); + ShowUI.showUninstallDialog(this); } @Nullable diff --git a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java index 7121032e7..08dd4ad97 100644 --- a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java @@ -17,6 +17,7 @@ import android.widget.Toast; import com.topjohnwu.magisk.asyncs.CheckUpdates; import com.topjohnwu.magisk.asyncs.HideManager; +import com.topjohnwu.magisk.asyncs.UpdateRepos; import com.topjohnwu.magisk.components.Activity; import com.topjohnwu.magisk.database.SuDatabaseHelper; import com.topjohnwu.magisk.utils.Shell; @@ -118,7 +119,9 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { } findPreference("clear").setOnPreferenceClickListener((pref) -> { - Utils.clearRepoCache(getActivity()); + mm.prefs.edit().remove(UpdateRepos.ETAG_KEY).apply(); + mm.repoDB.clearRepo(); + mm.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT); return true; }); @@ -204,9 +207,9 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { case "magiskhide": enabled = prefs.getBoolean("magiskhide", false); if (enabled) { - Utils.enableMagiskHide(); + Shell.su_raw("magiskhide --enable"); } else { - Utils.disableMagiskHide(); + Shell.su_raw("magiskhide --disable"); } break; case "hosts": diff --git a/app/src/main/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java b/app/src/main/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java index f72257394..42a3d83e8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java @@ -5,6 +5,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.support.design.widget.Snackbar; import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -16,6 +17,7 @@ import android.widget.TextView; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.asyncs.ParallelTask; import com.topjohnwu.magisk.components.SnackbarMaker; +import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; @@ -56,6 +58,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter { if (isChecked) { - Utils.addMagiskHide(info.packageName); + Shell.su_raw("magiskhide --add " + info.packageName); mHideList.add(info.packageName); } else { - Utils.rmMagiskHide(info.packageName); + Shell.su_raw("magiskhide --rm " + info.packageName); mHideList.remove(info.packageName); } }); @@ -132,8 +138,8 @@ public class ApplicationAdapter extends RecyclerView.Adapter(); String filter = constraint.toString().toLowerCase(); for (ApplicationInfo info : mOriginalList) { - if (Utils.lowercaseContains(info.loadLabel(pm), filter) - || Utils.lowercaseContains(info.packageName, filter)) { + if (lowercaseContains(info.loadLabel(pm), filter) + || lowercaseContains(info.packageName, filter)) { mList.add(info); } } @@ -160,7 +166,7 @@ public class ApplicationAdapter extends RecyclerView.Adapter a.loadLabel(pm).toString().toLowerCase() .compareTo(b.loadLabel(pm).toString().toLowerCase())); - mHideList = Utils.listMagiskHide(); + mHideList = Shell.su("magiskhide --ls"); return null; } diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java index 1561735a9..0e94b4d45 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java @@ -4,7 +4,7 @@ import android.content.Context; import com.topjohnwu.magisk.BuildConfig; import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.ShowUI; import com.topjohnwu.magisk.utils.WebService; import org.json.JSONException; @@ -65,9 +65,9 @@ public class CheckUpdates extends ParallelTask { if (mm == null) return; if (showNotification && mm.updateNotification) { if (BuildConfig.VERSION_CODE < mm.remoteManagerVersionCode) { - Utils.showManagerUpdateNotification(mm); + ShowUI.showManagerUpdateNotification(mm); } else if (mm.magiskVersionCode < mm.remoteMagiskVersionCode) { - Utils.showMagiskUpdateNotification(mm); + ShowUI.showMagiskUpdateNotification(mm); } } mm.updateCheckDone.publish(); diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java index db02ae15f..5069ddd4a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java @@ -14,6 +14,7 @@ import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.ZipUtils; import java.io.File; +import java.security.SecureRandom; import java.util.List; import java.util.jar.JarEntry; @@ -27,6 +28,27 @@ public class HideManager extends ParallelTask { super(context); } + private String genPackageName(String prefix, int length) { + StringBuilder builder = new StringBuilder(length); + builder.append(prefix); + length -= prefix.length(); + SecureRandom random = new SecureRandom(); + String base = "abcdefghijklmnopqrstuvwxyz"; + String alpha = base + base.toUpperCase(); + String full = alpha + "0123456789.........."; + char next, prev = '\0'; + for (int i = 0; i < length; ++i) { + if (prev == '.' || i == length - 1 || i == 0) { + next = alpha.charAt(random.nextInt(alpha.length())); + } else { + next = full.charAt(random.nextInt(full.length())); + } + builder.append(next); + prev = next; + } + return builder.toString(); + } + @Override protected void onPreExecute() { getMagiskManager().toast(R.string.hide_manager_toast, Toast.LENGTH_SHORT); @@ -67,7 +89,7 @@ public class HideManager extends ParallelTask { return false; // Patch binary XML with new package name - pkg = Utils.genPackageName("com.", UNHIDE_PKG_NAME.length - 1); + pkg = genPackageName("com.", UNHIDE_PKG_NAME.length - 1); System.arraycopy(pkg.getBytes(), 0, xml, offset, pkg.length()); asset.getOutputStream(je).write(xml); diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java index c59772702..e1042d60a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java @@ -5,7 +5,9 @@ import android.content.Context; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.container.Module; import com.topjohnwu.magisk.container.ValueSortedMap; -import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.Shell; + +import java.util.List; public class LoadModules extends ParallelTask { @@ -13,13 +15,18 @@ public class LoadModules extends ParallelTask { super(context); } + private List getModList() { + String command = "ls -d " + MagiskManager.MAGISK_PATH + "/* | grep -v lost+found"; + return Shell.su(command); + } + @Override protected Void doInBackground(Void... voids) { MagiskManager mm = getMagiskManager(); if (mm == null) return null; mm.moduleMap = new ValueSortedMap<>(); - for (String path : Utils.getModList(MagiskManager.MAGISK_PATH)) { + for (String path : getModList()) { Module module = new Module(path); mm.moduleMap.put(module.getId(), module); } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java b/app/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java new file mode 100644 index 000000000..a84b72b24 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java @@ -0,0 +1,276 @@ +package com.topjohnwu.magisk.utils; + +import android.app.Activity; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.TaskStackBuilder; +import android.support.v7.app.AlertDialog; +import android.widget.Toast; + +import com.topjohnwu.magisk.FlashActivity; +import com.topjohnwu.magisk.MagiskFragment; +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.SplashActivity; +import com.topjohnwu.magisk.asyncs.RestoreStockBoot; +import com.topjohnwu.magisk.components.AlertDialogBuilder; +import com.topjohnwu.magisk.receivers.DownloadReceiver; +import com.topjohnwu.magisk.receivers.ManagerUpdate; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +public class ShowUI { + private static final int SELECT_BOOT_IMG = 3; + private static final String UNINSTALLER = "magisk_uninstaller.sh"; + private static final int MAGISK_UPDATE_NOTIFICATION_ID = 1; + private static final int APK_UPDATE_NOTIFICATION_ID = 2; + + public static void showMagiskUpdateNotification(MagiskManager mm) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, MagiskManager.NOTIFICATION_CHANNEL); + builder.setSmallIcon(R.drawable.ic_magisk) + .setContentTitle(mm.getString(R.string.magisk_update_title)) + .setContentText(mm.getString(R.string.magisk_update_available, mm.remoteMagiskVersionString)) + .setVibrate(new long[]{0, 100, 100, 100}) + .setAutoCancel(true); + Intent intent = new Intent(mm, SplashActivity.class); + intent.putExtra(MagiskManager.INTENT_SECTION, "magisk"); + TaskStackBuilder stackBuilder = TaskStackBuilder.create(mm); + stackBuilder.addParentStack(SplashActivity.class); + stackBuilder.addNextIntent(intent); + PendingIntent pendingIntent = stackBuilder.getPendingIntent(MAGISK_UPDATE_NOTIFICATION_ID, + PendingIntent.FLAG_UPDATE_CURRENT); + builder.setContentIntent(pendingIntent); + NotificationManager notificationManager = + (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(MAGISK_UPDATE_NOTIFICATION_ID, builder.build()); + } + + public static void showManagerUpdateNotification(MagiskManager mm) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, MagiskManager.NOTIFICATION_CHANNEL); + builder.setSmallIcon(R.drawable.ic_magisk) + .setContentTitle(mm.getString(R.string.manager_update_title)) + .setContentText(mm.getString(R.string.manager_download_install)) + .setVibrate(new long[]{0, 100, 100, 100}) + .setAutoCancel(true); + Intent intent = new Intent(mm, ManagerUpdate.class); + intent.putExtra(MagiskManager.INTENT_LINK, mm.managerLink); + intent.putExtra(MagiskManager.INTENT_VERSION, mm.remoteManagerVersionString); + PendingIntent pendingIntent = PendingIntent.getBroadcast(mm, + APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); + builder.setContentIntent(pendingIntent); + NotificationManager notificationManager = + (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(APK_UPDATE_NOTIFICATION_ID, builder.build()); + } + + public static void showMagiskInstallDialog(MagiskFragment fragment, boolean enc, boolean verity) { + MagiskManager mm = Utils.getMagiskManager(fragment.getActivity()); + String filename = Utils.getLegalFilename("Magisk-v" + mm.remoteMagiskVersionString + ".zip"); + new AlertDialogBuilder(fragment.getActivity()) + .setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.magisk))) + .setMessage(mm.getString(R.string.repo_install_msg, filename)) + .setCancelable(true) + .setPositiveButton(R.string.install, (d, i) -> { + List options = new ArrayList<>(); + options.add(mm.getString(R.string.download_zip_only)); + options.add(mm.getString(R.string.patch_boot_file)); + if (Shell.rootAccess()) { + options.add(mm.getString(R.string.direct_install)); + } + List res = Shell.su("echo $SLOT"); + if (Utils.isValidShellResponse(res)) { + options.add(mm.getString(R.string.install_second_slot)); + } + char[] slot = Utils.isValidShellResponse(res) ? res.get(0).toCharArray() : null; + new AlertDialog.Builder(fragment.getActivity()) + .setTitle(R.string.select_method) + .setItems( + options.toArray(new String [0]), + (dialog, idx) -> { + String boot; + DownloadReceiver receiver = null; + switch (idx) { + case 1: + if (mm.remoteMagiskVersionCode < 1400) { + mm.toast(R.string.no_boot_file_patch_support, Toast.LENGTH_LONG); + return; + } + mm.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG); + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + fragment.startActivityForResult(intent, SELECT_BOOT_IMG, + (requestCode, resultCode, data) -> { + if (requestCode == SELECT_BOOT_IMG + && resultCode == Activity.RESULT_OK && data != null) { + Utils.dlAndReceive( + fragment.getActivity(), + new DownloadReceiver() { + @Override + public void onDownloadDone(Uri uri) { + Intent intent = new Intent(mm, FlashActivity.class); + intent.setData(uri) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .putExtra(FlashActivity.SET_BOOT, data.getData()) + .putExtra(FlashActivity.SET_ENC, enc) + .putExtra(FlashActivity.SET_VERITY, verity) + .putExtra(FlashActivity.SET_ACTION, FlashActivity.PATCH_BOOT); + mm.startActivity(intent); + } + }, + mm.magiskLink, + filename + ); + } + }); + return; + case 0: + receiver = new DownloadReceiver() { + @Override + public void onDownloadDone(Uri uri) { + Utils.showUriSnack(fragment.getActivity(), uri); + } + }; + break; + case 2: + boot = fragment.getSelectedBootImage(); + if (boot == null) + return; + receiver = new DownloadReceiver() { + @Override + public void onDownloadDone(Uri uri) { + Intent intent = new Intent(mm, FlashActivity.class); + intent.setData(uri) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .putExtra(FlashActivity.SET_BOOT, boot) + .putExtra(FlashActivity.SET_ENC, enc) + .putExtra(FlashActivity.SET_VERITY, verity) + .putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_MAGISK); + mm.startActivity(intent); + } + }; + break; + case 3: + assert (slot != null); + // Choose the other slot + if (slot[1] == 'a') slot[1] = 'b'; + else slot[1] = 'a'; + // Then find the boot image again + List ret = Shell.su( + "BOOTIMAGE=", + "SLOT=" + String.valueOf(slot), + "find_boot_image", + "echo \"$BOOTIMAGE\"" + ); + boot = Utils.isValidShellResponse(ret) ? ret.get(ret.size() - 1) : null; + Shell.su_raw("mount_partitions"); + if (boot == null) + return; + receiver = new DownloadReceiver() { + @Override + public void onDownloadDone(Uri uri) { + Intent intent = new Intent(mm, FlashActivity.class); + intent.setData(uri) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .putExtra(FlashActivity.SET_BOOT, boot) + .putExtra(FlashActivity.SET_ENC, enc) + .putExtra(FlashActivity.SET_VERITY, verity) + .putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_MAGISK); + mm.startActivity(intent); + } + }; + default: + } + Utils.dlAndReceive( + fragment.getActivity(), + receiver, + mm.magiskLink, + filename + ); + } + ).show(); + }) + .setNeutralButton(R.string.release_notes, (d, i) -> { + if (mm.releaseNoteLink != null) { + Intent openLink = new Intent(Intent.ACTION_VIEW, Uri.parse(mm.releaseNoteLink)); + openLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mm.startActivity(openLink); + } + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } + + public static void showManagerInstallDialog(Activity activity) { + MagiskManager mm = Utils.getMagiskManager(activity); + new AlertDialogBuilder(activity) + .setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name))) + .setMessage(mm.getString(R.string.repo_install_msg, + Utils.getLegalFilename("MagiskManager-v" + + mm.remoteManagerVersionString + ".apk"))) + .setCancelable(true) + .setPositiveButton(R.string.install, (d, i) -> { + Intent intent = new Intent(mm, ManagerUpdate.class); + intent.putExtra(MagiskManager.INTENT_LINK, mm.managerLink); + intent.putExtra(MagiskManager.INTENT_VERSION, mm.remoteManagerVersionString); + mm.sendBroadcast(intent); + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } + + public static void showUninstallDialog(MagiskFragment fragment) { + MagiskManager mm = Utils.getMagiskManager(fragment.getActivity()); + new AlertDialogBuilder(fragment.getActivity()) + .setTitle(R.string.uninstall_magisk_title) + .setMessage(R.string.uninstall_magisk_msg) + .setPositiveButton(R.string.complete_uninstall, (d, i) -> { + try { + InputStream in = mm.getAssets().open(UNINSTALLER); + File uninstaller = new File(mm.getCacheDir(), UNINSTALLER); + FileOutputStream out = new FileOutputStream(uninstaller); + byte[] bytes = new byte[1024]; + int read; + while ((read = in.read(bytes)) != -1) { + out.write(bytes, 0, read); + } + in.close(); + out.close(); + in = mm.getAssets().open(Utils.UTIL_FUNCTIONS); + File utils = new File(mm.getCacheDir(), Utils.UTIL_FUNCTIONS); + out = new FileOutputStream(utils); + while ((read = in.read(bytes)) != -1) { + out.write(bytes, 0, read); + } + in.close(); + out.close(); + Shell.su( + "cat " + uninstaller + " > /cache/" + UNINSTALLER, + "cat " + utils + " > /data/magisk/" + Utils.UTIL_FUNCTIONS + ); + mm.toast(R.string.uninstall_toast, Toast.LENGTH_LONG); + Shell.su_raw( + "sleep 5", + "pm uninstall " + mm.getApplicationInfo().packageName + ); + } catch (IOException e) { + e.printStackTrace(); + } + }) + .setNeutralButton(R.string.restore_stock_boot, (d, i) -> { + String boot = fragment.getSelectedBootImage(); + if (boot == null) return; + new RestoreStockBoot(mm, boot).exec(); + }) + .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 b63e7b54a..48f37390a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -3,11 +3,8 @@ package com.topjohnwu.magisk.utils; import android.Manifest; import android.app.Activity; import android.app.DownloadManager; -import android.app.NotificationManager; -import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.content.Context; -import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -22,30 +19,16 @@ import android.provider.OpenableColumns; import android.support.annotation.StringRes; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; -import android.support.v4.app.NotificationCompat; -import android.support.v4.app.TaskStackBuilder; import android.support.v4.content.ContextCompat; -import android.support.v7.app.AlertDialog; import android.text.TextUtils; import android.widget.Toast; -import com.topjohnwu.magisk.FlashActivity; -import com.topjohnwu.magisk.MagiskFragment; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.SplashActivity; -import com.topjohnwu.magisk.asyncs.RestoreStockBoot; -import com.topjohnwu.magisk.asyncs.UpdateRepos; -import com.topjohnwu.magisk.components.AlertDialogBuilder; import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.receivers.DownloadReceiver; -import com.topjohnwu.magisk.receivers.ManagerUpdate; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -54,14 +37,9 @@ import java.util.Locale; public class Utils { - public static final int SELECT_BOOT_IMG = 3; - public static final String UNINSTALLER = "magisk_uninstaller.sh"; public static final String UTIL_FUNCTIONS= "util_functions.sh"; public static boolean isDownloading = false; - private static final int MAGISK_UPDATE_NOTIFICATION_ID = 1; - private static final int APK_UPDATE_NOTIFICATION_ID = 2; - public static boolean itemExist(String path) { String command = "[ -e " + path + " ] && echo true || echo false"; List ret = Shell.su(command); @@ -79,11 +57,6 @@ public class Utils { Shell.su_raw(command); } - public static List getModList(String path) { - String command = "ls -d " + path + "/* | grep -v lost+found"; - return Shell.su(command); - } - public static List readFile(String path) { String command = "cat " + path + " | sed '$a\\ ' | sed '$d'"; return Shell.su(command); @@ -123,10 +96,6 @@ public class Utils { .replace("#", "").replace("@", "").replace("*", ""); } - public static boolean lowercaseContains(CharSequence string, CharSequence nonNullLowercaseSearch) { - return !TextUtils.isEmpty(string) && string.toString().toLowerCase().contains(nonNullLowercaseSearch); - } - public static boolean isValidShellResponse(List list) { if (list != null && list.size() != 0) { // Check if all empty @@ -149,13 +118,6 @@ public class Utils { return (MagiskManager) context.getApplicationContext(); } - public static void clearRepoCache(Context context) { - MagiskManager mm = getMagiskManager(context); - mm.prefs.edit().remove(UpdateRepos.ETAG_KEY).apply(); - mm.repoDB.clearRepo(); - mm.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT); - } - public static String getNameFromUri(Context context, Uri uri) { String name = null; try (Cursor c = context.getContentResolver().query(uri, null, null, null, null)) { @@ -187,64 +149,6 @@ public class Utils { return networkInfo != null && networkInfo.isConnected(); } - public static void showMagiskUpdateNotification(MagiskManager mm) { - NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, MagiskManager.NOTIFICATION_CHANNEL); - builder.setSmallIcon(R.drawable.ic_magisk) - .setContentTitle(mm.getString(R.string.magisk_update_title)) - .setContentText(mm.getString(R.string.magisk_update_available, mm.remoteMagiskVersionString)) - .setVibrate(new long[]{0, 100, 100, 100}) - .setAutoCancel(true); - Intent intent = new Intent(mm, SplashActivity.class); - intent.putExtra(MagiskManager.INTENT_SECTION, "magisk"); - TaskStackBuilder stackBuilder = TaskStackBuilder.create(mm); - stackBuilder.addParentStack(SplashActivity.class); - stackBuilder.addNextIntent(intent); - PendingIntent pendingIntent = stackBuilder.getPendingIntent(MAGISK_UPDATE_NOTIFICATION_ID, - PendingIntent.FLAG_UPDATE_CURRENT); - builder.setContentIntent(pendingIntent); - NotificationManager notificationManager = - (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(MAGISK_UPDATE_NOTIFICATION_ID, builder.build()); - } - - public static void showManagerUpdateNotification(MagiskManager mm) { - NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, MagiskManager.NOTIFICATION_CHANNEL); - builder.setSmallIcon(R.drawable.ic_magisk) - .setContentTitle(mm.getString(R.string.manager_update_title)) - .setContentText(mm.getString(R.string.manager_download_install)) - .setVibrate(new long[]{0, 100, 100, 100}) - .setAutoCancel(true); - Intent intent = new Intent(mm, ManagerUpdate.class); - intent.putExtra(MagiskManager.INTENT_LINK, mm.managerLink); - intent.putExtra(MagiskManager.INTENT_VERSION, mm.remoteManagerVersionString); - PendingIntent pendingIntent = PendingIntent.getBroadcast(mm, - APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); - builder.setContentIntent(pendingIntent); - NotificationManager notificationManager = - (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(APK_UPDATE_NOTIFICATION_ID, builder.build()); - } - - public static void enableMagiskHide() { - Shell.su_raw("magiskhide --enable"); - } - - public static void disableMagiskHide() { - Shell.su_raw("magiskhide --disable"); - } - - public static List listMagiskHide() { - return Shell.su("magiskhide --ls"); - } - - public static void addMagiskHide(String pkg) { - Shell.su_raw("magiskhide --add " + pkg); - } - - public static void rmMagiskHide(String pkg) { - Shell.su_raw("magiskhide --rm " + pkg); - } - public static String getLocaleString(Context context, Locale locale, @StringRes int id) { Configuration config = context.getResources().getConfiguration(); config.setLocale(locale); @@ -283,27 +187,6 @@ public class Utils { return locales; } - public static String genPackageName(String prefix, int length) { - StringBuilder builder = new StringBuilder(length); - builder.append(prefix); - length -= prefix.length(); - SecureRandom random = new SecureRandom(); - String base = "abcdefghijklmnopqrstuvwxyz"; - String alpha = base + base.toUpperCase(); - String full = alpha + "0123456789.........."; - char next, prev = '\0'; - for (int i = 0; i < length; ++i) { - if (prev == '.' || i == length - 1 || i == 0) { - next = alpha.charAt(random.nextInt(alpha.length())); - } else { - next = full.charAt(random.nextInt(full.length())); - } - builder.append(next); - prev = next; - } - return builder.toString(); - } - public static void runWithPermission(Context context, String permission, Runnable callback) { if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) { // Passed in context should be an activity if not granted, need to show dialog! @@ -317,208 +200,6 @@ public class Utils { } } - public static void showMagiskInstallDialog(MagiskFragment fragment, boolean enc, boolean verity) { - MagiskManager mm = getMagiskManager(fragment.getActivity()); - String filename = getLegalFilename("Magisk-v" + mm.remoteMagiskVersionString + ".zip"); - new AlertDialogBuilder(fragment.getActivity()) - .setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.magisk))) - .setMessage(mm.getString(R.string.repo_install_msg, filename)) - .setCancelable(true) - .setPositiveButton(R.string.install, (d, i) -> { - List options = new ArrayList<>(); - options.add(mm.getString(R.string.download_zip_only)); - options.add(mm.getString(R.string.patch_boot_file)); - if (Shell.rootAccess()) { - options.add(mm.getString(R.string.direct_install)); - } - List res = Shell.su("echo $SLOT"); - if (isValidShellResponse(res)) { - options.add(mm.getString(R.string.install_second_slot)); - } - char[] slot = isValidShellResponse(res) ? res.get(0).toCharArray() : null; - new AlertDialog.Builder(fragment.getActivity()) - .setTitle(R.string.select_method) - .setItems( - options.toArray(new String [0]), - (dialog, idx) -> { - String boot; - DownloadReceiver receiver = null; - switch (idx) { - case 1: - if (mm.remoteMagiskVersionCode < 1400) { - mm.toast(R.string.no_boot_file_patch_support, Toast.LENGTH_LONG); - return; - } - mm.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG); - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("*/*"); - fragment.startActivityForResult(intent, SELECT_BOOT_IMG, - (requestCode, resultCode, data) -> { - if (requestCode == SELECT_BOOT_IMG - && resultCode == Activity.RESULT_OK && data != null) { - dlAndReceive( - fragment.getActivity(), - new DownloadReceiver() { - @Override - public void onDownloadDone(Uri uri) { - Intent intent = new Intent(mm, FlashActivity.class); - intent.setData(uri) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(FlashActivity.SET_BOOT, data.getData()) - .putExtra(FlashActivity.SET_ENC, enc) - .putExtra(FlashActivity.SET_VERITY, verity) - .putExtra(FlashActivity.SET_ACTION, FlashActivity.PATCH_BOOT); - mm.startActivity(intent); - } - }, - mm.magiskLink, - filename - ); - } - }); - return; - case 0: - receiver = new DownloadReceiver() { - @Override - public void onDownloadDone(Uri uri) { - showUriSnack(fragment.getActivity(), uri); - } - }; - break; - case 2: - boot = fragment.getSelectedBootImage(); - if (boot == null) - return; - receiver = new DownloadReceiver() { - @Override - public void onDownloadDone(Uri uri) { - Intent intent = new Intent(mm, FlashActivity.class); - intent.setData(uri) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(FlashActivity.SET_BOOT, boot) - .putExtra(FlashActivity.SET_ENC, enc) - .putExtra(FlashActivity.SET_VERITY, verity) - .putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_MAGISK); - mm.startActivity(intent); - } - }; - break; - case 3: - assert (slot != null); - // Choose the other slot - if (slot[1] == 'a') slot[1] = 'b'; - else slot[1] = 'a'; - // Then find the boot image again - List ret = Shell.su( - "BOOTIMAGE=", - "SLOT=" + String.valueOf(slot), - "find_boot_image", - "echo \"$BOOTIMAGE\"" - ); - boot = isValidShellResponse(ret) ? ret.get(ret.size() - 1) : null; - Shell.su_raw("mount_partitions"); - if (boot == null) - return; - receiver = new DownloadReceiver() { - @Override - public void onDownloadDone(Uri uri) { - Intent intent = new Intent(mm, FlashActivity.class); - intent.setData(uri) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(FlashActivity.SET_BOOT, boot) - .putExtra(FlashActivity.SET_ENC, enc) - .putExtra(FlashActivity.SET_VERITY, verity) - .putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_MAGISK); - mm.startActivity(intent); - } - }; - default: - } - Utils.dlAndReceive( - fragment.getActivity(), - receiver, - mm.magiskLink, - filename - ); - } - ).show(); - }) - .setNeutralButton(R.string.release_notes, (d, i) -> { - if (mm.releaseNoteLink != null) { - Intent openLink = new Intent(Intent.ACTION_VIEW, Uri.parse(mm.releaseNoteLink)); - openLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mm.startActivity(openLink); - } - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } - - public static void showManagerInstallDialog(Activity activity) { - MagiskManager mm = Utils.getMagiskManager(activity); - new AlertDialogBuilder(activity) - .setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name))) - .setMessage(mm.getString(R.string.repo_install_msg, - Utils.getLegalFilename("MagiskManager-v" + - mm.remoteManagerVersionString + ".apk"))) - .setCancelable(true) - .setPositiveButton(R.string.install, (d, i) -> { - Intent intent = new Intent(mm, ManagerUpdate.class); - intent.putExtra(MagiskManager.INTENT_LINK, mm.managerLink); - intent.putExtra(MagiskManager.INTENT_VERSION, mm.remoteManagerVersionString); - mm.sendBroadcast(intent); - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } - - public static void showUninstallDialog(MagiskFragment fragment) { - MagiskManager mm = Utils.getMagiskManager(fragment.getActivity()); - new AlertDialogBuilder(fragment.getActivity()) - .setTitle(R.string.uninstall_magisk_title) - .setMessage(R.string.uninstall_magisk_msg) - .setPositiveButton(R.string.complete_uninstall, (d, i) -> { - try { - InputStream in = mm.getAssets().open(UNINSTALLER); - File uninstaller = new File(mm.getCacheDir(), UNINSTALLER); - FileOutputStream out = new FileOutputStream(uninstaller); - byte[] bytes = new byte[1024]; - int read; - while ((read = in.read(bytes)) != -1) { - out.write(bytes, 0, read); - } - in.close(); - out.close(); - in = mm.getAssets().open(UTIL_FUNCTIONS); - File utils = new File(mm.getCacheDir(), UTIL_FUNCTIONS); - out = new FileOutputStream(utils); - while ((read = in.read(bytes)) != -1) { - out.write(bytes, 0, read); - } - in.close(); - out.close(); - Shell.su( - "cat " + uninstaller + " > /cache/" + UNINSTALLER, - "cat " + utils + " > /data/magisk/" + UTIL_FUNCTIONS - ); - mm.toast(R.string.uninstall_toast, Toast.LENGTH_LONG); - Shell.su_raw( - "sleep 5", - "pm uninstall " + mm.getApplicationInfo().packageName - ); - } catch (IOException e) { - e.printStackTrace(); - } - }) - .setNeutralButton(R.string.restore_stock_boot, (d, i) -> { - String boot = fragment.getSelectedBootImage(); - if (boot == null) return; - new RestoreStockBoot(mm, boot).exec(); - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } - public static boolean useFDE(Context context) { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && context.getSystemService(DevicePolicyManager.class).getStorageEncryptionStatus()