From a3f0ef8e772f4a85a01c7efebb248b959c03edd6 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 21 Feb 2017 03:30:37 +0800 Subject: [PATCH] Many improvements and bug fixes Close #114 --- .../com/topjohnwu/magisk/InstallFragment.java | 233 ++++++++++-------- .../topjohnwu/magisk/MagiskHideFragment.java | 3 +- .../topjohnwu/magisk/MagiskLogFragment.java | 11 +- .../com/topjohnwu/magisk/MagiskManager.java | 7 +- .../com/topjohnwu/magisk/MainActivity.java | 21 +- .../com/topjohnwu/magisk/ReposFragment.java | 5 +- .../topjohnwu/magisk/SettingsActivity.java | 15 +- .../com/topjohnwu/magisk/StatusFragment.java | 40 +-- .../magisk/adapters/SuLogAdapter.java | 4 +- .../magisk/asyncs/GetBootBlocks.java | 7 +- .../com/topjohnwu/magisk/asyncs/LoadApps.java | 3 +- .../topjohnwu/magisk/asyncs/LoadRepos.java | 3 +- .../topjohnwu/magisk/asyncs/MagiskHide.java | 9 +- .../magisk/asyncs/ProcessMagiskZip.java | 9 +- .../magisk/asyncs/ProcessRepoZip.java | 5 +- .../magisk/components/AlertDialogBuilder.java | 9 +- .../magisk/components/SnackbarMaker.java | 4 +- .../magisk/database/RepoDatabaseHelper.java | 6 +- .../magisk/database/SuDatabaseHelper.java | 16 +- .../magisk/database/SuLogDatabaseHelper.java | 14 +- .../com/topjohnwu/magisk/module/Module.java | 3 +- .../com/topjohnwu/magisk/module/Repo.java | 4 - .../magisk/superuser/SuReceiver.java | 10 +- .../magisk/superuser/SuRequestActivity.java | 8 +- .../topjohnwu/magisk/utils/CallbackEvent.java | 9 +- .../com/topjohnwu/magisk/utils/Shell.java | 6 +- .../com/topjohnwu/magisk/utils/Utils.java | 3 +- .../topjohnwu/magisk/utils/WebService.java | 5 +- .../com/topjohnwu/magisk/utils/ZipUtils.java | 27 +- app/src/main/res/layout/fragment_install.xml | 4 +- app/src/main/res/values-zh-rTW/strings.xml | 8 +- app/src/main/res/values/colors.xml | 3 - app/src/main/res/values/strings.xml | 2 + 33 files changed, 304 insertions(+), 212 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/InstallFragment.java b/app/src/main/java/com/topjohnwu/magisk/InstallFragment.java index 0c988afaf..e8522140a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/InstallFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/InstallFragment.java @@ -6,6 +6,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.CountDownTimer; import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; import android.support.v7.widget.CardView; import android.view.LayoutInflater; import android.view.View; @@ -19,6 +20,7 @@ import android.widget.TextView; import com.topjohnwu.magisk.asyncs.ProcessMagiskZip; import com.topjohnwu.magisk.components.AlertDialogBuilder; import com.topjohnwu.magisk.components.Fragment; +import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.receivers.DownloadReceiver; import com.topjohnwu.magisk.utils.CallbackEvent; import com.topjohnwu.magisk.utils.Shell; @@ -34,6 +36,7 @@ import java.util.Locale; import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnClick; import butterknife.Unbinder; public class InstallFragment extends Fragment implements CallbackEvent.Listener { @@ -41,108 +44,126 @@ public class InstallFragment extends Fragment implements CallbackEvent.Listener< private static final String UNINSTALLER = "magisk_uninstaller.sh"; - private Unbinder unbinder; @BindView(R.id.current_version_title) TextView currentVersionTitle; @BindView(R.id.install_title) TextView installTitle; @BindView(R.id.block_spinner) Spinner spinner; @BindView(R.id.detect_bootimage) Button detectButton; - @BindView(R.id.flash_button) CardView flashButton; + @BindView(R.id.install_button) CardView installButton; + @BindView(R.id.install_text) TextView installText; @BindView(R.id.uninstall_button) CardView uninstallButton; @BindView(R.id.keep_force_enc) CheckBox keepEncChkbox; @BindView(R.id.keep_verity) CheckBox keepVerityChkbox; + @OnClick(R.id.detect_bootimage) + public void toAutoDetect() { + if (magiskManager.bootBlock != null) { + spinner.setSelection(0); + } + } + + @OnClick(R.id.install_button) + public void install() { + String bootImage = null; + if (magiskManager.blockList != null) { + int idx = spinner.getSelectedItemPosition(); + if (magiskManager.bootBlock != null) { + if (idx > 0) { + bootImage = magiskManager.blockList.get(idx - 1); + } + } else { + if (idx > 0) { + bootImage = magiskManager.blockList.get(idx - 1); + } else { + SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG); + } + } + } + final String finalBootImage = bootImage; + String filename = "Magisk-v" + magiskManager.remoteMagiskVersion + ".zip"; + new AlertDialogBuilder(getActivity()) + .setTitle(getString(R.string.repo_install_title, getString(R.string.magisk))) + .setMessage(getString(R.string.repo_install_msg, filename)) + .setCancelable(true) + .setPositiveButton(Shell.rootAccess() ? R.string.install : R.string.download, + (dialogInterface, i) -> Utils.dlAndReceive( + getActivity(), + new DownloadReceiver() { + private String boot = finalBootImage; + private boolean enc = keepEncChkbox.isChecked(); + private boolean verity = keepVerityChkbox.isChecked(); + + @Override + public void onDownloadDone(Uri uri) { + new ProcessMagiskZip(getActivity(), uri, boot, enc, verity).exec(); + } + }, + magiskManager.magiskLink, + Utils.getLegalFilename(filename))) + .setNeutralButton(R.string.release_notes, (dialog, which) -> { + magiskManager.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink))); + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } + + @OnClick(R.id.uninstall_button) + public void uninstall() { + new AlertDialogBuilder(getActivity()) + .setTitle(R.string.uninstall_magisk_title) + .setMessage(R.string.uninstall_magisk_msg) + .setPositiveButton(R.string.yes, (dialogInterface, i) -> { + try { + InputStream in = magiskManager.getAssets().open(UNINSTALLER); + File uninstaller = new File(magiskManager.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(); + ProgressDialog progress = new ProgressDialog(getActivity()); + progress.setTitle(R.string.reboot); + progress.show(); + new CountDownTimer(5000, 1000) { + @Override + public void onTick(long millisUntilFinished) { + progress.setMessage(getString(R.string.reboot_countdown, millisUntilFinished / 1000)); + } + + @Override + public void onFinish() { + progress.setMessage(getString(R.string.reboot_countdown, 0)); + Shell.su(true, "mv -f " + uninstaller + " /cache/" + UNINSTALLER, + "reboot"); + } + }.start(); + } catch (IOException e) { + e.printStackTrace(); + } + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } + + private Unbinder unbinder; + private MagiskManager magiskManager; + @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_install, container, false); unbinder = ButterKnife.bind(this, v); - detectButton.setOnClickListener(v1 -> toAutoDetect()); - if (getApplication().magiskVersion < 0) + magiskManager = getApplication(); + if (magiskManager.magiskVersion < 0) { currentVersionTitle.setText(getString(R.string.current_magisk_title, getString(R.string.version_none))); - else - currentVersionTitle.setText(getString(R.string.current_magisk_title, "v" + getApplication().magiskVersionString)); - installTitle.setText(getString(R.string.install_magisk_title, "v" + String.format(Locale.US, "%.1f", getApplication().remoteMagiskVersion))); - flashButton.setOnClickListener(v1 -> { - String bootImage; - if (getApplication().bootBlock != null) { - if (spinner.getSelectedItemPosition() > 0) - bootImage = getApplication().blockList.get(spinner.getSelectedItemPosition() - 1); - else - bootImage = getApplication().bootBlock; - } else { - bootImage = getApplication().blockList.get(spinner.getSelectedItemPosition()); - } - String filename = "Magisk-v" + getApplication().remoteMagiskVersion + ".zip"; - new AlertDialogBuilder(getActivity()) - .setTitle(getString(R.string.repo_install_title, getString(R.string.magisk))) - .setMessage(getString(R.string.repo_install_msg, filename)) - .setCancelable(true) - .setPositiveButton(R.string.install, (dialogInterface, i) -> Utils.dlAndReceive( - getActivity(), - new DownloadReceiver() { - private String boot = bootImage; - private boolean enc = keepEncChkbox.isChecked(); - private boolean verity = keepVerityChkbox.isChecked(); - - @Override - public void onDownloadDone(Uri uri) { - new ProcessMagiskZip(getActivity(), uri, boot, enc, verity).exec(); - } - }, - getApplication().magiskLink, - Utils.getLegalFilename(filename))) - .setNeutralButton(R.string.release_notes, (dialog, which) -> { - getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getApplication().releaseNoteLink))); - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - }); - if (getApplication().magiskVersion < 10.3) { - uninstallButton.setVisibility(View.GONE); } else { - uninstallButton.setOnClickListener(vi -> { - new AlertDialogBuilder(getActivity()) - .setTitle(R.string.uninstall_magisk_title) - .setMessage(R.string.uninstall_magisk_msg) - .setPositiveButton(R.string.yes, (dialogInterface, i) -> { - try { - InputStream in = getActivity().getAssets().open(UNINSTALLER); - File uninstaller = new File(getActivity().getCacheDir().getAbsolutePath() + "/" + 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(); - ProgressDialog progress = new ProgressDialog(getActivity()); - progress.setTitle(R.string.reboot); - progress.show(); - new CountDownTimer(5000, 1000) { - @Override - public void onTick(long millisUntilFinished) { - progress.setMessage(getString(R.string.reboot_countdown, millisUntilFinished / 1000)); - } - - @Override - public void onFinish() { - progress.setMessage(getString(R.string.reboot_countdown, 0)); - Shell.su(true, "cp -af " + uninstaller + " /cache/" + UNINSTALLER, - "reboot"); - } - }.start(); - } catch (IOException e) { - e.printStackTrace(); - } - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - }); + currentVersionTitle.setText(getString(R.string.current_magisk_title, "v" + magiskManager.magiskVersionString)); } + installTitle.setText(getString(R.string.install_magisk_title, "v" + String.format(Locale.US, "%.1f", magiskManager.remoteMagiskVersion))); - if (getApplication().blockDetectionDone.isTriggered) { - updateUI(); - } + updateUI(); return v; } @@ -152,19 +173,33 @@ public class InstallFragment extends Fragment implements CallbackEvent.Listener< } private void updateUI() { - List items = new ArrayList<>(getApplication().blockList); - if (getApplication().bootBlock != null) - items.add(0, getString(R.string.auto_detect, getApplication().bootBlock)); - ArrayAdapter adapter = new ArrayAdapter<>(getActivity(), - android.R.layout.simple_spinner_item, items); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spinner.setAdapter(adapter); - toAutoDetect(); - } + if (magiskManager.blockList == null || !Shell.rootAccess()) { + uninstallButton.setVisibility(View.GONE); + installText.setText(R.string.download); + detectButton.setEnabled(false); + keepEncChkbox.setEnabled(false); + keepVerityChkbox.setEnabled(false); + spinner.setEnabled(false); + } else { + uninstallButton.setVisibility(magiskManager.magiskVersion > 10.3 ? View.VISIBLE : View.GONE); + installText.setText(R.string.download_install); + detectButton.setEnabled(true); + keepEncChkbox.setEnabled(true); + keepVerityChkbox.setEnabled(true); + spinner.setEnabled(true); - private void toAutoDetect() { - if (getApplication().bootBlock != null) { - spinner.setSelection(0); + List items = new ArrayList<>(); + if (magiskManager.bootBlock != null) { + items.add(getString(R.string.auto_detect, magiskManager.bootBlock)); + } else { + items.add(getString(R.string.cannot_auto_detect)); + } + items.addAll(magiskManager.blockList); + ArrayAdapter adapter = new ArrayAdapter<>(getActivity(), + android.R.layout.simple_spinner_item, items); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner.setAdapter(adapter); + toAutoDetect(); } } @@ -172,12 +207,12 @@ public class InstallFragment extends Fragment implements CallbackEvent.Listener< public void onStart() { super.onStart(); getActivity().setTitle(R.string.install); - getApplication().blockDetectionDone.register(this); + magiskManager.blockDetectionDone.register(this); } @Override public void onStop() { - getApplication().blockDetectionDone.unRegister(this); + magiskManager.blockDetectionDone.unRegister(this); super.onStop(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java index 2f610a9b5..05e3191c3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java @@ -71,8 +71,9 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen } }; - if (getApplication().magiskHideDone.isTriggered) + if (getApplication().magiskHideDone.isTriggered) { onTrigger(getApplication().magiskHideDone); + } return view; } diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java index 2cbe5886a..00ae6a9af 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java @@ -162,8 +162,9 @@ public class MagiskLogFragment extends Fragment { return false; } - if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { return false; + } Calendar now = Calendar.getInstance(); String filename = String.format( @@ -175,8 +176,9 @@ public class MagiskLogFragment extends Fragment { targetFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/MagiskManager/" + filename); if ((!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs()) - || (targetFile.exists() && !targetFile.delete())) + || (targetFile.exists() && !targetFile.delete())) { return false; + } List in = Utils.readFile(MAGISK_LOG); @@ -214,10 +216,11 @@ public class MagiskLogFragment extends Fragment { break; case 2: bool = (boolean) o; - if (bool) + if (bool) { Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG).show(); - else + } else { Toast.makeText(getActivity(), getString(R.string.logs_save_failed), Toast.LENGTH_LONG).show(); + } break; } } diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java index 7a1d5b064..6e056c0d4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java @@ -125,9 +125,9 @@ public class MagiskManager extends Application { } if (isSuClient) { ret = Shell.sh("getprop persist.sys.root_access"); - if (Utils.isValidShellResponse(ret)) + if (Utils.isValidShellResponse(ret)) { suAccessState = Integer.parseInt(ret.get(0)); - else { + } else { Shell.su(true, "setprop persist.sys.root_access 3"); suAccessState = 3; } @@ -160,8 +160,9 @@ public class MagiskManager extends Application { magiskHideStarted = false; } - if (!magiskHide && magiskHideStarted) + if (magiskHideStarted) { magiskHide = true; + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/MainActivity.java b/app/src/main/java/com/topjohnwu/magisk/MainActivity.java index 2e9cfcc4c..4c1da9d80 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MainActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/MainActivity.java @@ -131,14 +131,16 @@ public class MainActivity extends Activity private void checkHideSection() { Menu menu = navigationView.getMenu(); - if (Shell.rootAccess()) { - menu.findItem(R.id.magiskhide).setVisible( - getApplicationContext().magiskVersion >= 8 && prefs.getBoolean("magiskhide", false)); - menu.findItem(R.id.modules).setVisible(getApplicationContext().magiskVersion >= 4); - menu.findItem(R.id.downloads).setVisible(getApplicationContext().magiskVersion >= 4); - menu.findItem(R.id.log).setVisible(true); - menu.findItem(R.id.superuser).setVisible(getApplicationContext().isSuClient); - } + menu.findItem(R.id.magiskhide).setVisible( + Shell.rootAccess() && getApplicationContext().magiskVersion >= 8 + && prefs.getBoolean("magiskhide", false)); + menu.findItem(R.id.modules).setVisible( + Shell.rootAccess() && getApplicationContext().magiskVersion >= 4); + menu.findItem(R.id.downloads).setVisible( + Shell.rootAccess() && getApplicationContext().magiskVersion >= 4); + menu.findItem(R.id.log).setVisible(Shell.rootAccess()); + menu.findItem(R.id.superuser).setVisible( + Shell.rootAccess() && getApplicationContext().isSuClient); menu.findItem(R.id.install).setVisible(getApplicationContext().remoteMagiskVersion > 0); } @@ -179,6 +181,7 @@ public class MainActivity extends Activity } public void navigate(int itemId) { + int bak = mDrawerItem; mDrawerItem = itemId; navigationView.setCheckedItem(itemId); switch (itemId) { @@ -205,9 +208,11 @@ public class MainActivity extends Activity break; case R.id.settings: startActivity(new Intent(this, SettingsActivity.class)); + mDrawerItem = bak; break; case R.id.app_about: startActivity(new Intent(this, AboutActivity.class)); + mDrawerItem = bak; break; } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java index 108d415df..69888a704 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -133,10 +133,11 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener module.getVersionCode()) + if (repo.getVersionCode() > module.getVersionCode()) { mUpdateRepos.add(repo); - else + } else { mInstalledRepos.add(repo); + } } else { mOthersRepos.add(repo); } diff --git a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java index 42d1246de..2fa2230cf 100644 --- a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java @@ -112,10 +112,12 @@ public class SettingsActivity extends Activity { prefScreen.removePreference(magiskCategory); prefScreen.removePreference(suCategory); } else { - if (!getApplication().isSuClient) + if (!getApplication().isSuClient) { prefScreen.removePreference(suCategory); - if (getApplication().magiskVersion < 11) + } + if (getApplication().magiskVersion < 11) { prefScreen.removePreference(magiskCategory); + } if (getApplication().disabled) { busybox.setEnabled(false); magiskHide.setEnabled(false); @@ -146,8 +148,8 @@ public class SettingsActivity extends Activity { enabled = prefs.getBoolean("dark_theme", false); if (getApplication().isDarkTheme != enabled) { getApplication().isDarkTheme = enabled; - getActivity().finish(); getApplication().reloadMainActivity.trigger(); + getActivity().recreate(); } break; case "disable": @@ -195,9 +197,12 @@ public class SettingsActivity extends Activity { .setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide().enable()) .setCancelable(false) .show(); - } else new MagiskHide().enable(); - } else + } else { + new MagiskHide().enable(); + } + } else { new MagiskHide().disable(); + } break; case "hosts": enabled = prefs.getBoolean("hosts", false); diff --git a/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java b/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java index b02efc1dd..1eaabc472 100644 --- a/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java @@ -22,6 +22,7 @@ import com.topjohnwu.magisk.utils.Utils; import butterknife.BindColor; import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnClick; import butterknife.Unbinder; public class StatusFragment extends Fragment implements CallbackEvent.Listener { @@ -53,7 +54,27 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener { - safetyNetProgress.setVisibility(View.VISIBLE); - safetyNetContainer.setBackgroundColor(trans); - safetyNetIcon.setImageResource(0); - safetyNetStatusText.setText(R.string.checking_safetyNet_status); - Utils.checkSafetyNet(getApplication()); - }); - - magiskStatusContainer.setOnClickListener(view -> { - ((MainActivity) getActivity()).navigationView.setCheckedItem(R.id.install); - FragmentTransaction transaction = getFragmentManager().beginTransaction(); - transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out); - try { - transaction.replace(R.id.content_frame, new InstallFragment(), "install").commit(); - } catch (IllegalStateException ignored) {} - }); - if (getApplication().magiskVersion < 0 && Shell.rootAccess() && !noDialog) { noDialog = true; new AlertDialogBuilder(getActivity()) diff --git a/app/src/main/java/com/topjohnwu/magisk/adapters/SuLogAdapter.java b/app/src/main/java/com/topjohnwu/magisk/adapters/SuLogAdapter.java index 4a8219872..90dfcf394 100644 --- a/app/src/main/java/com/topjohnwu/magisk/adapters/SuLogAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/adapters/SuLogAdapter.java @@ -109,7 +109,9 @@ public class SuLogAdapter { @Override public void onBindGroupViewHolder(LogGroupViewHolder holder, int flatPosition, ExpandableGroup group) { holder.date.setText(group.getTitle()); - if (isGroupExpanded(flatPosition)) holder.expand(); + if (isGroupExpanded(flatPosition)) { + holder.expand(); + } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/GetBootBlocks.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/GetBootBlocks.java index 489467942..ff33ccf4e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/GetBootBlocks.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/GetBootBlocks.java @@ -13,10 +13,9 @@ public class GetBootBlocks extends SerialTask { @Override protected Void doInBackground(Void... params) { - if (Shell.rootAccess()) { - magiskManager.blockList = Shell.su("ls /dev/block | grep mmc"); - if (magiskManager.bootBlock == null) - magiskManager.bootBlock = Utils.detectBootImage(); + magiskManager.blockList = Shell.su("ls /dev/block | grep mmc"); + if (magiskManager.bootBlock == null) { + magiskManager.bootBlock = Utils.detectBootImage(); } return null; } diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadApps.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadApps.java index 14a91e86c..3efa36d3d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadApps.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadApps.java @@ -22,8 +22,9 @@ public class LoadApps extends ParallelTask { List list = pm.getInstalledApplications(0); for (Iterator i = list.iterator(); i.hasNext(); ) { ApplicationInfo info = i.next(); - if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) + if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) { i.remove(); + } } Collections.sort(list, (a, b) -> a.loadLabel(pm).toString().toLowerCase() .compareTo(b.loadLabel(pm).toString().toLowerCase())); diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadRepos.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadRepos.java index ca2cb87b1..bd7e2e574 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadRepos.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadRepos.java @@ -96,8 +96,9 @@ public class LoadRepos extends ParallelTask { Logger.dev("LoadRepos: Update cached repo " + id); repo.update(updatedDate); } - if (repo.getId() != null) + if (repo.getId() != null) { magiskManager.repoMap.put(id, repo); + } } catch (BaseModule.CacheModException ignored) {} } diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/MagiskHide.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/MagiskHide.java index ebadd06c9..cc6218fe8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/MagiskHide.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/MagiskHide.java @@ -21,15 +21,17 @@ public class MagiskHide extends SerialTask { protected Void doInBackground(Object... params) { String command = (String) params[0]; List ret = Shell.su(MagiskManager.MAGISK_HIDE_PATH + command); - if (isList) + if (isList) { magiskManager.magiskHideList = ret; + } return null; } @Override protected void onPostExecute(Void v) { - if (isList) + if (isList) { magiskManager.magiskHideDone.trigger(); + } } public void add(CharSequence packageName) { @@ -50,8 +52,7 @@ public class MagiskHide extends SerialTask { public void list() { isList = true; - if (magiskManager == null) - return; + if (magiskManager == null) return; exec("list"); } diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessMagiskZip.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessMagiskZip.java index abca9c78c..91ecfb434 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessMagiskZip.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessMagiskZip.java @@ -45,7 +45,8 @@ public class ProcessMagiskZip extends ParallelTask { ZipUtils.unzip(magiskManager.getContentResolver().openInputStream(mUri), tempdir); // Running in parallel mode, open new shell Shell.su(true, - "echo \"BOOTIMAGE=/dev/block/" + mBoot + "\" > /dev/.magisk", + "rm -f /dev/.magisk", + (mBoot != null) ? "echo \"BOOTIMAGE=/dev/block/" + mBoot + "\" >> /dev/.magisk" : "", "echo \"KEEPFORCEENCRYPT=" + String.valueOf(mEnc) + "\" >> /dev/.magisk", "echo \"KEEPVERITY=" + String.valueOf(mVerity) + "\" >> /dev/.magisk", "mkdir -p " + MagiskManager.TMP_FOLDER_PATH, @@ -66,13 +67,14 @@ public class ProcessMagiskZip extends ParallelTask { @Override protected void onPostExecute(Boolean result) { progressDialog.dismiss(); - if (result) + if (result) { new FlashZip(activity, mUri) { @Override protected boolean unzipAndCheck() throws Exception { // Don't need to check, as it is downloaded in correct form return true; } + @Override protected void onSuccess() { new SerialTask(activity) { @@ -87,7 +89,8 @@ public class ProcessMagiskZip extends ParallelTask { super.onSuccess(); } }.exec(); - else + } else { Utils.showUriSnack(activity, mUri); + } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java index 16e134fe4..f1c3223b6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java @@ -103,10 +103,11 @@ public class ProcessRepoZip extends ParallelTask { protected void onPostExecute(Boolean result) { progressDialog.dismiss(); if (result) { - if (Shell.rootAccess() && mInstall) + if (Shell.rootAccess() && mInstall) { new FlashZip(activity, mUri).exec(); - else + } else { Utils.showUriSnack(activity, mUri); + } } else { Toast.makeText(activity, R.string.process_error, Toast.LENGTH_LONG).show(); diff --git a/app/src/main/java/com/topjohnwu/magisk/components/AlertDialogBuilder.java b/app/src/main/java/com/topjohnwu/magisk/components/AlertDialogBuilder.java index d9ed1a229..a94f27a68 100644 --- a/app/src/main/java/com/topjohnwu/magisk/components/AlertDialogBuilder.java +++ b/app/src/main/java/com/topjohnwu/magisk/components/AlertDialogBuilder.java @@ -93,8 +93,9 @@ public class AlertDialogBuilder extends AlertDialog.Builder { positive.setText(text); positiveListener = listener; positive.setOnClickListener((v) -> { - if (positiveListener != null) + if (positiveListener != null) { positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE); + } dialog.dismiss(); }); return this; @@ -112,8 +113,9 @@ public class AlertDialogBuilder extends AlertDialog.Builder { negative.setText(text); negativeListener = listener; negative.setOnClickListener((v) -> { - if (negativeListener != null) + if (negativeListener != null) { negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE); + } dialog.dismiss(); }); return this; @@ -131,8 +133,9 @@ public class AlertDialogBuilder extends AlertDialog.Builder { neutral.setText(text); neutralListener = listener; neutral.setOnClickListener((v) -> { - if (neutralListener != null) + if (neutralListener != null) { neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL); + } dialog.dismiss(); }); return this; diff --git a/app/src/main/java/com/topjohnwu/magisk/components/SnackbarMaker.java b/app/src/main/java/com/topjohnwu/magisk/components/SnackbarMaker.java index bdbfd174c..966a34fba 100644 --- a/app/src/main/java/com/topjohnwu/magisk/components/SnackbarMaker.java +++ b/app/src/main/java/com/topjohnwu/magisk/components/SnackbarMaker.java @@ -3,7 +3,6 @@ package com.topjohnwu.magisk.components; import android.app.Activity; import android.support.annotation.StringRes; import android.support.design.widget.Snackbar; -import android.text.TextUtils; import android.view.View; import android.widget.TextView; @@ -34,8 +33,7 @@ public class SnackbarMaker { private static void setup(Snackbar snack) { TextView text = ButterKnife.findById(snack.getView(), android.support.design.R.id.snackbar_text); - text.setMaxLines(2); - text.setEllipsize(TextUtils.TruncateAt.START); + text.setMaxLines(Integer.MAX_VALUE); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/database/RepoDatabaseHelper.java b/app/src/main/java/com/topjohnwu/magisk/database/RepoDatabaseHelper.java index a8d803c19..625d42a68 100644 --- a/app/src/main/java/com/topjohnwu/magisk/database/RepoDatabaseHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/database/RepoDatabaseHelper.java @@ -40,8 +40,9 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper { public void addRepoMap(ValueSortedMap map) { SQLiteDatabase db = getWritableDatabase(); Collection list = map.values(); - for (Repo repo : list) + for (Repo repo : list) { db.replace(TABLE_NAME, null, repo.getContentValues()); + } db.close(); } @@ -54,8 +55,9 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper { public void removeRepo(ValueSortedMap map) { SQLiteDatabase db = getWritableDatabase(); Collection list = map.values(); - for (Repo repo : list) + for (Repo repo : list) { db.delete(TABLE_NAME, "id=?", new String[] { repo.getId() }); + } db.close(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java b/app/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java index c5ac90eab..7ab223043 100644 --- a/app/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java @@ -22,15 +22,18 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { - db.execSQL( - "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " + - "(uid INT, package_name TEXT, app_name TEXT, policy INT, " + - "until INT, logging INT, notification INT, " + - "PRIMARY KEY(uid))"); + onUpgrade(db, 0, DATABASE_VER); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion == 0) { + db.execSQL( + "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " + + "(uid INT, package_name TEXT, app_name TEXT, policy INT, " + + "until INT, logging INT, notification INT, " + + "PRIMARY KEY(uid))"); + } // Currently new database, no upgrading } @@ -45,8 +48,9 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { Policy policy = null; SQLiteDatabase db = getReadableDatabase(); try (Cursor c = db.query(TABLE_NAME, null, "uid=?", new String[] { String.valueOf(uid) }, null, null, null)) { - if (c.moveToNext()) + if (c.moveToNext()) { policy = new Policy(c); + } } db.close(); return policy; diff --git a/app/src/main/java/com/topjohnwu/magisk/database/SuLogDatabaseHelper.java b/app/src/main/java/com/topjohnwu/magisk/database/SuLogDatabaseHelper.java index 05f3eee29..d5ba28b76 100644 --- a/app/src/main/java/com/topjohnwu/magisk/database/SuLogDatabaseHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/database/SuLogDatabaseHelper.java @@ -25,14 +25,17 @@ public class SuLogDatabaseHelper extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { - db.execSQL( - "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, " + - "from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " + - "to_uid INT, action INT, time INT, command TEXT)"); + onUpgrade(db, 0, DATABASE_VER); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion == 0) { + db.execSQL( + "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " + + "to_uid INT, action INT, time INT, command TEXT)"); + } // Currently new database, no upgrading } @@ -63,8 +66,9 @@ public class SuLogDatabaseHelper extends SQLiteOpenHelper { db.delete(TABLE_NAME, "time < ?", new String[] { String.valueOf( System.currentTimeMillis() / 1000 - magiskManager.suLogTimeout * 86400) }); try (Cursor c = db.query(TABLE_NAME, null, selection, null, null, null, "time DESC")) { - while (c.moveToNext()) + while (c.moveToNext()) { ret.add(new SuLogEntry(c)); + } } db.close(); return ret; diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Module.java b/app/src/main/java/com/topjohnwu/magisk/module/Module.java index 5996d26fa..5889e0e62 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -21,8 +21,9 @@ public class Module extends BaseModule { setId(path.substring(sep + 1)); } - if (getName() == null) + if (getName() == null) { setName(getId()); + } Logger.dev("Creating Module, id: " + getId()); diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index 12e69792d..d758b7984 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -60,10 +60,6 @@ public class Repo extends BaseModule { return String.format(ZIP_URL, repoName); } - public String getLogUrl() { - return String.format(FILE_URL, repoName, "changelog.txt"); - } - public String getManifestUrl() { return String.format(FILE_URL, repoName, "module.prop"); } diff --git a/app/src/main/java/com/topjohnwu/magisk/superuser/SuReceiver.java b/app/src/main/java/com/topjohnwu/magisk/superuser/SuReceiver.java index f4bde58b0..66ed3649a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/superuser/SuReceiver.java +++ b/app/src/main/java/com/topjohnwu/magisk/superuser/SuReceiver.java @@ -38,10 +38,12 @@ public class SuReceiver extends BroadcastReceiver { SuDatabaseHelper suDbHelper = new SuDatabaseHelper(context); policy = suDbHelper.getPolicy(fromUid); - if (policy == null) try { - policy = new Policy(fromUid, context.getPackageManager()); - } catch (Throwable throwable) { - return; + if (policy == null) { + try { + policy = new Policy(fromUid, context.getPackageManager()); + } catch (Throwable throwable) { + return; + } } magiskManager.initSuConfigs(); diff --git a/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java b/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java index 784225f6f..7d71b2ebd 100644 --- a/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java @@ -76,8 +76,9 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene @Override public void onEvent(int fileEvent, String path) { if (fileEvent == FileObserver.DELETE_SELF) { - if (event != null) + if (event != null) { event.trigger(); + } finish(); } } @@ -147,8 +148,9 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene public void onTrigger(CallbackEvent event) { Policy policy = event.getResult(); String response = "socket:DENY"; - if (policy != null &&policy.policy == Policy.ALLOW ) + if (policy != null &&policy.policy == Policy.ALLOW ) { response = "socket:ALLOW"; + } try { socket.getOutputStream().write((response).getBytes()); } catch (Exception ignored) {} @@ -176,7 +178,7 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene @Override protected Boolean doInBackground(Void... params) { - try{ + try { socket = new LocalSocket(); socket.connect(new LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM)); diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/CallbackEvent.java b/app/src/main/java/com/topjohnwu/magisk/utils/CallbackEvent.java index c5768ff31..5e4a02c85 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/CallbackEvent.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/CallbackEvent.java @@ -10,8 +10,9 @@ public class CallbackEvent { private Set> listeners; public void register(Listener l) { - if (listeners == null) + if (listeners == null) { listeners = new HashSet<>(); + } listeners.add(l); } @@ -20,8 +21,9 @@ public class CallbackEvent { } public void unRegister(Listener l) { - if (listeners != null) + if (listeners != null) { listeners.remove(l); + } } public void trigger() { @@ -32,8 +34,9 @@ public class CallbackEvent { result = r; isTriggered = true; if (listeners != null) { - for (Listener listener : listeners) + for (Listener listener : listeners) { listener.onTrigger(this); + } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java b/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java index aaa4c1f66..9701bde2d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java @@ -120,11 +120,13 @@ public class Shell { StreamGobbler STDOUT; // Create the default shell if not init - if (!newShell && !isInit) + if (!newShell && !isInit) { init(); + } - if (!newShell && !rootAccess()) + if (!newShell && !rootAccess()) { return null; + } if (newShell) { res = Collections.synchronizedList(new ArrayList()); 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 d55dd6aed..b4ded8670 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -114,8 +114,9 @@ public class Utils { "echo \"${BOOTIMAGE##*/}\"" }; List ret = Shell.su(commands); - if (isValidShellResponse(ret)) + if (isValidShellResponse(ret)) { return ret.get(0); + } return null; } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/WebService.java b/app/src/main/java/com/topjohnwu/magisk/utils/WebService.java index a33639d44..99afd5536 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/WebService.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/WebService.java @@ -77,10 +77,11 @@ public class WebService { StringBuilder result = new StringBuilder(); boolean first = true; for (Map.Entry entry : params.entrySet()) { - if (first) + if (first) { first = false; - else + } else { result.append("&"); + } result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); result.append("="); diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java b/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java index 2f0b6ab35..b74388599 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java @@ -112,14 +112,17 @@ public class ZipUtils { // Remove the top directory from the path path = entry.getName().substring(entry.getName().indexOf("/") + 1); // If it's the top folder, ignore it - if (path.isEmpty()) + if (path.isEmpty()) { continue; + } // Don't include placeholder - if (path.contains("system/placeholder")) + if (path.contains("system/placeholder")) { continue; + } dest.putNextEntry(new JarEntry(path)); - while((size = source.read(buffer, 0, 2048)) != -1) + while((size = source.read(buffer, 0, 2048)) != -1) { dest.write(buffer, 0, size); + } } source.close(); dest.close(); @@ -149,17 +152,20 @@ public class ZipUtils { Enumeration e = zipfile.entries(); while(e.hasMoreElements()) { entry = e.nextElement(); - if (!entry.getName().contains(path) || entry.isDirectory()) + if (!entry.getName().contains(path) || entry.isDirectory()){ // Ignore directories, only create files continue; + } Logger.dev("ZipUtils: Extracting: " + entry); is = zipfile.getInputStream(entry); dest = new File(folder, entry.getName()); - if (dest.getParentFile().mkdirs()) + if (dest.getParentFile().mkdirs()) { dest.createNewFile(); + } out = new FileOutputStream(dest); - while ((count = is.read(data, 0, 4096)) != -1) + while ((count = is.read(data, 0, 4096)) != -1) { out.write(data, 0, count); + } out.flush(); out.close(); is.close(); @@ -178,16 +184,19 @@ public class ZipUtils { byte data[] = new byte[4096]; try (JarInputStream zipfile = new JarInputStream(file)) { while((entry = zipfile.getNextJarEntry()) != null) { - if (!entry.getName().contains(path) || entry.isDirectory()) + if (!entry.getName().contains(path) || entry.isDirectory()) { // Ignore directories, only create files continue; + } Logger.dev("ZipUtils: Extracting: " + entry); dest = new File(folder, entry.getName()); - if (dest.getParentFile().mkdirs()) + if (dest.getParentFile().mkdirs()) { dest.createNewFile(); + } out = new FileOutputStream(dest); - while ((count = zipfile.read(data, 0, 4096)) != -1) + while ((count = zipfile.read(data, 0, 4096)) != -1) { out.write(data, 0, count); + } out.flush(); out.close(); } diff --git a/app/src/main/res/layout/fragment_install.xml b/app/src/main/res/layout/fragment_install.xml index 38b0dd4f7..f6565c7cc 100644 --- a/app/src/main/res/layout/fragment_install.xml +++ b/app/src/main/res/layout/fragment_install.xml @@ -159,7 +159,7 @@ (自動) %1$s - Boot 鏡像位置 + Boot 映像位置 偵測 高級設置 保持強制加密 @@ -181,13 +181,15 @@ 目標 UID:\u0020 "指令: " 關閉 - Zip 已被儲存到:[內部儲存空間]%1$s + Zip 已被儲存到:\n[內部儲存空間]%1$s 處裡失敗 下載 處理中 解除安裝 Magisk - 這將會刪除所有模組,MagiskSU,並有可能在目前未加密的情況下加密的的資料\n你確定要繼續嗎? + 這將會刪除所有模組,MagiskSU,並有可能在目前資料未加密的情況下進行加密\n你確定要繼續嗎? (無) + 請手動選取 boot 映像位置 + (無法自動偵測) diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 4388aaf60..68f9a017d 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -13,9 +13,6 @@ #2196F3 #FFC107 - #bf360c - #000000 - #dedede #e0e0e0 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 16e84ee4a..bfc3b3b40 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -38,6 +38,7 @@ (Auto) %1$s + (Cannot auto detect) Boot Image Location Detect Advanced Settings @@ -124,6 +125,7 @@ Process error The zip is stored in:\n[Internal Storage]%1$s Processing + Please manually select a boot image! General