diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java index cf52261f0..03e15df5e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java @@ -229,6 +229,7 @@ public class MagiskManager extends Application { "export PATH=" + BUSYBOXPATH + ":$PATH", ". " + utils, "mount_partitions", + "BOOTIMAGE=", "find_boot_image", "migrate_boot_backup" ); 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 77656ee49..7aad8d0b8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -332,101 +332,137 @@ public class Utils { 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)); - } - new AlertDialog.Builder(fragment.getActivity()) - .setTitle(R.string.select_method) - .setItems( - options.toArray(new String [0]), - (dialog, idx) -> { - 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 - ); - } - }); + .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.getShell(mm).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; - case 0: - receiver = new DownloadReceiver() { - @Override - public void onDownloadDone(Uri uri) { - showUriSnack(fragment.getActivity(), uri); + } + 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 + ); } - }; - break; - case 2: - final String 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) + }); + 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.getShell(mm).su( + "BOOTIMAGE=", + "SLOT=" + String.valueOf(slot), + "find_boot_image", + "echo \"$BOOTIMAGE\"" + ); + boot = isValidShellResponse(ret) ? ret.get(ret.size() - 1) : null; + Shell.getShell(mm).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); - } - }; - break; - } - Utils.dlAndReceive( - mm, - receiver, - mm.magiskLink, - filename - ); + mm.startActivity(intent); + } + }; + default: } - ).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(); + Utils.dlAndReceive( + mm, + 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) { @@ -450,58 +486,58 @@ public class Utils { 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(); - ProgressDialog progress = new ProgressDialog(fragment.getActivity()); - progress.setTitle(R.string.reboot); - progress.show(); - new CountDownTimer(5000, 1000) { - @Override - public void onTick(long millisUntilFinished) { - progress.setMessage(mm.getString(R.string.reboot_countdown, - millisUntilFinished / 1000)); - } - - @Override - public void onFinish() { - progress.setMessage(mm.getString(R.string.reboot_countdown, 0)); - Shell.getShell(mm).su_raw( - "mv -f " + uninstaller + " /cache/" + UNINSTALLER, - "mv -f " + utils + " /data/magisk/" + UTIL_FUNCTIONS, - "reboot" - ); - } - }.start(); - } catch (IOException e) { - e.printStackTrace(); + .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); } - }) - .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(); + 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(); + ProgressDialog progress = new ProgressDialog(fragment.getActivity()); + progress.setTitle(R.string.reboot); + progress.show(); + new CountDownTimer(5000, 1000) { + @Override + public void onTick(long millisUntilFinished) { + progress.setMessage(mm.getString(R.string.reboot_countdown, + millisUntilFinished / 1000)); + } + + @Override + public void onFinish() { + progress.setMessage(mm.getString(R.string.reboot_countdown, 0)); + Shell.getShell(mm).su_raw( + "mv -f " + uninstaller + " /cache/" + UNINSTALLER, + "mv -f " + utils + " /data/magisk/" + UTIL_FUNCTIONS, + "reboot" + ); + } + }.start(); + } 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(); } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b6dfcae2f..d3c87bed6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -114,6 +114,7 @@ Download Zip Only Patch Boot Image File Direct Install (Recommend) + Install to Second Slot (After OTA) Select Method Target Magisk version doesn\'t support boot image file patching Select stock boot image dump in .img or .img.tar format