mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-28 12:35:26 +00:00
Massive Zip flashing refactoring
This commit is contained in:
parent
f9ab060403
commit
23c84a7803
@ -18,8 +18,8 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -86,7 +86,7 @@ public class AboutActivity extends Activity {
|
|||||||
result = Html.fromHtml(changes);
|
result = Html.fromHtml(changes);
|
||||||
}
|
}
|
||||||
appChangelog.setOnClickListener(v -> {
|
appChangelog.setOnClickListener(v -> {
|
||||||
AlertDialog d = Utils.getAlertDialogBuilder(this)
|
AlertDialog d = new AlertDialogBuilder(this)
|
||||||
.setTitle(R.string.app_changelog)
|
.setTitle(R.string.app_changelog)
|
||||||
.setMessage(result)
|
.setMessage(result)
|
||||||
.setPositiveButton(android.R.string.ok, null)
|
.setPositiveButton(android.R.string.ok, null)
|
||||||
@ -105,7 +105,7 @@ public class AboutActivity extends Activity {
|
|||||||
} else {
|
} else {
|
||||||
result = Html.fromHtml(getString(R.string.app_developers_));
|
result = Html.fromHtml(getString(R.string.app_developers_));
|
||||||
}
|
}
|
||||||
AlertDialog d = Utils.getAlertDialogBuilder(this)
|
AlertDialog d = new AlertDialogBuilder(this)
|
||||||
.setTitle(R.string.app_developers)
|
.setTitle(R.string.app_developers)
|
||||||
.setMessage(result)
|
.setMessage(result)
|
||||||
.setPositiveButton(android.R.string.ok, null)
|
.setPositiveButton(android.R.string.ok, null)
|
||||||
|
@ -16,8 +16,10 @@ import android.widget.CheckBox;
|
|||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
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.Fragment;
|
||||||
import com.topjohnwu.magisk.receivers.MagiskDlReceiver;
|
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
@ -67,13 +69,22 @@ public class InstallFragment extends Fragment implements CallbackEvent.Listener<
|
|||||||
bootImage = getApplication().blockList.get(spinner.getSelectedItemPosition());
|
bootImage = getApplication().blockList.get(spinner.getSelectedItemPosition());
|
||||||
}
|
}
|
||||||
String filename = "Magisk-v" + getApplication().remoteMagiskVersion + ".zip";
|
String filename = "Magisk-v" + getApplication().remoteMagiskVersion + ".zip";
|
||||||
Utils.getAlertDialogBuilder(getActivity())
|
new AlertDialogBuilder(getActivity())
|
||||||
.setTitle(getString(R.string.repo_install_title, getString(R.string.magisk)))
|
.setTitle(getString(R.string.repo_install_title, getString(R.string.magisk)))
|
||||||
.setMessage(getString(R.string.repo_install_msg, filename))
|
.setMessage(getString(R.string.repo_install_msg, filename))
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive(
|
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive(
|
||||||
getActivity(),
|
getActivity(),
|
||||||
new MagiskDlReceiver(bootImage, keepEncChkbox.isChecked(), keepVerityChkbox.isChecked()),
|
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,
|
getApplication().magiskLink,
|
||||||
Utils.getLegalFilename(filename)))
|
Utils.getLegalFilename(filename)))
|
||||||
.setNeutralButton(R.string.check_release_notes, (dialog, which) -> {
|
.setNeutralButton(R.string.check_release_notes, (dialog, which) -> {
|
||||||
@ -86,7 +97,7 @@ public class InstallFragment extends Fragment implements CallbackEvent.Listener<
|
|||||||
uninstallButton.setVisibility(View.GONE);
|
uninstallButton.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
uninstallButton.setOnClickListener(vi -> {
|
uninstallButton.setOnClickListener(vi -> {
|
||||||
Utils.getAlertDialogBuilder(getActivity())
|
new AlertDialogBuilder(getActivity())
|
||||||
.setTitle("Uninstall Magisk")
|
.setTitle("Uninstall Magisk")
|
||||||
.setMessage("This will remove all modules, MagiskSU, and potentially re-encrypt your device\nAre you sure to process?")
|
.setMessage("This will remove all modules, MagiskSU, and potentially re-encrypt your device\nAre you sure to process?")
|
||||||
.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
|
.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
|
||||||
|
@ -26,6 +26,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.SerialTask;
|
import com.topjohnwu.magisk.asyncs.SerialTask;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
@ -121,7 +122,7 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Snackbar.make(txtLog, R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
SnackbarMaker.make(txtLog, R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,7 +151,7 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
Shell.su("echo > " + MAGISK_LOG);
|
Shell.su("echo > " + MAGISK_LOG);
|
||||||
Snackbar.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -14,7 +14,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.github.clans.fab.FloatingActionButton;
|
import com.github.clans.fab.FloatingActionButton;
|
||||||
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
||||||
import com.topjohnwu.magisk.asyncs.FlashZIP;
|
import com.topjohnwu.magisk.asyncs.FlashZip;
|
||||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.module.Module;
|
||||||
@ -87,7 +87,7 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener<
|
|||||||
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||||
// Get the URI of the selected file
|
// Get the URI of the selected file
|
||||||
final Uri uri = data.getData();
|
final Uri uri = data.getData();
|
||||||
new FlashZIP(getActivity(), uri).exec();
|
new FlashZip(getActivity(), uri).exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import android.widget.Toast;
|
|||||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||||
import com.topjohnwu.magisk.asyncs.SerialTask;
|
import com.topjohnwu.magisk.asyncs.SerialTask;
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
@ -188,7 +189,7 @@ public class SettingsActivity extends Activity {
|
|||||||
enabled = prefs.getBoolean("magiskhide", false);
|
enabled = prefs.getBoolean("magiskhide", false);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (!getApplication().isSuClient) {
|
if (!getApplication().isSuClient) {
|
||||||
Utils.getAlertDialogBuilder(getActivity())
|
new AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.no_magisksu_title)
|
.setTitle(R.string.no_magisksu_title)
|
||||||
.setMessage(R.string.no_magisksu_msg)
|
.setMessage(R.string.no_magisksu_msg)
|
||||||
.setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide().enable())
|
.setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide().enable())
|
||||||
|
@ -15,6 +15,7 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
@ -97,7 +98,7 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
|
|||||||
|
|
||||||
if (getApplication().magiskVersion < 0 && Shell.rootAccess() && !noDialog) {
|
if (getApplication().magiskVersion < 0 && Shell.rootAccess() && !noDialog) {
|
||||||
noDialog = true;
|
noDialog = true;
|
||||||
Utils.getAlertDialogBuilder(getActivity())
|
new AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.no_magisk_title)
|
.setTitle(R.string.no_magisk_title)
|
||||||
.setMessage(R.string.no_magisk_msg)
|
.setMessage(R.string.no_magisk_msg)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
@ -229,7 +230,7 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
|
|||||||
magiskCheckUpdatesProgress.setVisibility(View.GONE);
|
magiskCheckUpdatesProgress.setVisibility(View.GONE);
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
|
|
||||||
updateMagisk = Utils.getAlertDialogBuilder(getActivity())
|
updateMagisk = new AlertDialogBuilder(getActivity())
|
||||||
.setTitle(R.string.magisk_update_title)
|
.setTitle(R.string.magisk_update_title)
|
||||||
.setMessage(getString(R.string.magisk_update_message, getApplication().remoteMagiskVersion))
|
.setMessage(getString(R.string.magisk_update_message, getApplication().remoteMagiskVersion))
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
|
@ -14,6 +14,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
import com.topjohnwu.magisk.asyncs.MagiskHide;
|
||||||
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -76,11 +77,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
if (SNLIST.contains(info.packageName)) {
|
if (SNLIST.contains(info.packageName)) {
|
||||||
holder.checkBox.setChecked(true);
|
holder.checkBox.setChecked(true);
|
||||||
holder.checkBox.setEnabled(false);
|
holder.checkBox.setEnabled(false);
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v ->
|
||||||
Snackbar snackbar = Snackbar.make(holder.itemView, R.string.safetyNet_hide_notice, Snackbar.LENGTH_LONG);
|
SnackbarMaker.make(holder.itemView,
|
||||||
((TextView) snackbar.getView().findViewById(android.support.design.R.id.snackbar_text)).setMaxLines(2);
|
R.string.safetyNet_hide_notice, Snackbar.LENGTH_LONG).show()
|
||||||
snackbar.show();
|
);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
holder.checkBox.setEnabled(true);
|
holder.checkBox.setEnabled(true);
|
||||||
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
holder.checkBox.setChecked(mHideList.contains(info.packageName));
|
||||||
|
@ -13,6 +13,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.SerialTask;
|
import com.topjohnwu.magisk.asyncs.SerialTask;
|
||||||
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.module.Module;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
|||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void v) {
|
protected void onPostExecute(Void v) {
|
||||||
int snack = isChecked ? R.string.disable_file_removed : R.string.disable_file_created;
|
int snack = isChecked ? R.string.disable_file_removed : R.string.disable_file_created;
|
||||||
Snackbar.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}.exec());
|
}.exec());
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
|
|||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void v) {
|
protected void onPostExecute(Void v) {
|
||||||
int snack = removed ? R.string.remove_file_deleted : R.string.remove_file_created;
|
int snack = removed ? R.string.remove_file_deleted : R.string.remove_file_created;
|
||||||
Snackbar.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
|
||||||
updateDeleteButton(holder, module);
|
updateDeleteButton(holder, module);
|
||||||
}
|
}
|
||||||
}.exec());
|
}.exec());
|
||||||
|
@ -15,9 +15,10 @@ import android.widget.Switch;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
import com.topjohnwu.magisk.superuser.Policy;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -70,7 +71,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
policy.policy = isChecked ? Policy.ALLOW : Policy.DENY;
|
policy.policy = isChecked ? Policy.ALLOW : Policy.DENY;
|
||||||
String message = v.getContext().getString(
|
String message = v.getContext().getString(
|
||||||
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
|
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
|
||||||
Snackbar.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.addPolicy(policy);
|
dbHelper.addPolicy(policy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -80,7 +81,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
policy.notification = isChecked;
|
policy.notification = isChecked;
|
||||||
String message = v.getContext().getString(
|
String message = v.getContext().getString(
|
||||||
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
|
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
|
||||||
Snackbar.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.addPolicy(policy);
|
dbHelper.addPolicy(policy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -90,18 +91,18 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
policy.logging = isChecked;
|
policy.logging = isChecked;
|
||||||
String message = v.getContext().getString(
|
String message = v.getContext().getString(
|
||||||
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
|
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
|
||||||
Snackbar.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.addPolicy(policy);
|
dbHelper.addPolicy(policy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
holder.delete.setOnClickListener(v -> Utils.getAlertDialogBuilder(v.getContext())
|
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
|
||||||
.setTitle(R.string.su_revoke_title)
|
.setTitle(R.string.su_revoke_title)
|
||||||
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
|
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
|
||||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||||
policyList.remove(position);
|
policyList.remove(position);
|
||||||
notifyItemRemoved(position);
|
notifyItemRemoved(position);
|
||||||
notifyItemRangeChanged(position, policyList.size());
|
notifyItemRangeChanged(position, policyList.size());
|
||||||
Snackbar.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
|
SnackbarMaker.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
|
||||||
Snackbar.LENGTH_SHORT).show();
|
Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.deletePolicy(policy.uid);
|
dbHelper.deletePolicy(policy.uid);
|
||||||
})
|
})
|
||||||
|
@ -17,8 +17,10 @@ import android.widget.LinearLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.module.Repo;
|
import com.topjohnwu.magisk.module.Repo;
|
||||||
import com.topjohnwu.magisk.receivers.RepoDlReceiver;
|
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
import com.topjohnwu.magisk.utils.WebWindow;
|
import com.topjohnwu.magisk.utils.WebWindow;
|
||||||
|
|
||||||
@ -75,13 +77,18 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
|
|||||||
});
|
});
|
||||||
holder.updateImage.setOnClickListener(view -> {
|
holder.updateImage.setOnClickListener(view -> {
|
||||||
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
|
String filename = repo.getName() + "-" + repo.getVersion() + ".zip";
|
||||||
Utils.getAlertDialogBuilder(context)
|
new AlertDialogBuilder(context)
|
||||||
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
|
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
|
||||||
.setMessage(context.getString(R.string.repo_install_msg, filename))
|
.setMessage(context.getString(R.string.repo_install_msg, filename))
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive(
|
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive(
|
||||||
context,
|
context,
|
||||||
new RepoDlReceiver(),
|
new DownloadReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onDownloadDone(Uri uri) {
|
||||||
|
new ProcessRepoZip(activity, uri).exec();
|
||||||
|
}
|
||||||
|
},
|
||||||
repo.getZipUrl(),
|
repo.getZipUrl(),
|
||||||
Utils.getLegalFilename(filename)))
|
Utils.getLegalFilename(filename)))
|
||||||
.setNegativeButton(R.string.no_thanks, null)
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
|
@ -2,13 +2,12 @@ package com.topjohnwu.magisk.asyncs;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.OpenableColumns;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
@ -22,46 +21,29 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class FlashZIP extends SerialTask<Void, String, Integer> {
|
public class FlashZip extends SerialTask<Void, String, Integer> {
|
||||||
|
|
||||||
protected Uri mUri;
|
private Uri mUri;
|
||||||
protected File mCachedFile;
|
private File mCachedFile, mScriptFile, mCheckFile;
|
||||||
|
|
||||||
private String mFilename;
|
private String mFilename;
|
||||||
private ProgressDialog progress;
|
private ProgressDialog progress;
|
||||||
|
|
||||||
public FlashZIP(Activity context, Uri uri, String filename) {
|
public FlashZip(Activity context, Uri uri) {
|
||||||
super(context);
|
super(context);
|
||||||
mUri = uri;
|
mUri = uri;
|
||||||
mFilename = filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FlashZIP(Activity context, Uri uri) {
|
mCachedFile = new File(magiskManager.getCacheDir(), "install.zip");
|
||||||
super(context);
|
mScriptFile = new File(magiskManager.getCacheDir(), "/META-INF/com/google/android/update-binary");
|
||||||
mUri = uri;
|
mCheckFile = new File(mScriptFile.getParent(), "updater-script");
|
||||||
|
|
||||||
// Try to get the filename ourselves
|
// Try to get the filename ourselves
|
||||||
Cursor c = magiskManager.getContentResolver().query(uri, null, null, null, null);
|
mFilename = Utils.getNameFromUri(magiskManager, mUri);
|
||||||
if (c != null) {
|
|
||||||
int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
|
||||||
c.moveToFirst();
|
|
||||||
if (nameIndex != -1) {
|
|
||||||
mFilename = c.getString(nameIndex);
|
|
||||||
}
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
if (mFilename == null) {
|
|
||||||
int idx = uri.getPath().lastIndexOf('/');
|
|
||||||
mFilename = uri.getPath().substring(idx + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void preProcessing() throws Throwable {
|
private void copyToCache() throws Throwable {
|
||||||
}
|
|
||||||
|
|
||||||
protected void copyToCache() throws Throwable {
|
|
||||||
publishProgress(magiskManager.getString(R.string.copying_msg));
|
publishProgress(magiskManager.getString(R.string.copying_msg));
|
||||||
mCachedFile = new File(magiskManager.getCacheDir().getAbsolutePath() + "/install.zip");
|
|
||||||
if (mCachedFile.exists() && !mCachedFile.delete()) {
|
if (mCachedFile.exists() && !mCachedFile.delete()) {
|
||||||
Logger.error("FlashZip: Error while deleting already existing file");
|
Logger.error("FlashZip: Error while deleting already existing file");
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
@ -73,9 +55,9 @@ public class FlashZIP extends SerialTask<Void, String, Integer> {
|
|||||||
byte buffer[] = new byte[1024];
|
byte buffer[] = new byte[1024];
|
||||||
int length;
|
int length;
|
||||||
if (in == null) throw new FileNotFoundException();
|
if (in == null) throw new FileNotFoundException();
|
||||||
while ((length = in.read(buffer)) > 0) {
|
while ((length = in.read(buffer)) > 0)
|
||||||
outputStream.write(buffer, 0, length);
|
outputStream.write(buffer, 0, length);
|
||||||
}
|
|
||||||
Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath());
|
Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath());
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Logger.error("FlashZip: Invalid Uri");
|
Logger.error("FlashZip: Invalid Uri");
|
||||||
@ -86,13 +68,21 @@ public class FlashZIP extends SerialTask<Void, String, Integer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean unzipAndCheck() {
|
protected boolean unzipAndCheck() throws Exception {
|
||||||
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android");
|
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android");
|
||||||
List<String> ret;
|
List<String> ret;
|
||||||
ret = Utils.readFile(mCachedFile.getParent() + "/META-INF/com/google/android/updater-script");
|
ret = Utils.readFile(mCheckFile.getPath());
|
||||||
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
|
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int cleanup(int ret) {
|
||||||
|
Shell.su(
|
||||||
|
"rm -rf " + mCachedFile.getParent() + "/*",
|
||||||
|
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
progress = new ProgressDialog(activity);
|
progress = new ProgressDialog(activity);
|
||||||
@ -110,17 +100,11 @@ public class FlashZIP extends SerialTask<Void, String, Integer> {
|
|||||||
Logger.dev("FlashZip Running... " + mFilename);
|
Logger.dev("FlashZip Running... " + mFilename);
|
||||||
List<String> ret;
|
List<String> ret;
|
||||||
try {
|
try {
|
||||||
preProcessing();
|
|
||||||
copyToCache();
|
copyToCache();
|
||||||
} catch (Throwable e) {
|
if (!unzipAndCheck()) return cleanup(0);
|
||||||
e.printStackTrace();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!unzipAndCheck()) return 0;
|
|
||||||
publishProgress(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
|
publishProgress(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
|
||||||
ret = Shell.su(
|
ret = Shell.su(
|
||||||
"BOOTMODE=true sh " + mCachedFile.getParent() +
|
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile,
|
||||||
"/META-INF/com/google/android/update-binary dummy 1 " + mCachedFile.getPath(),
|
|
||||||
"if [ $? -eq 0 ]; then echo true; else echo false; fi"
|
"if [ $? -eq 0 ]; then echo true; else echo false; fi"
|
||||||
);
|
);
|
||||||
if (!Utils.isValidShellResponse(ret)) return -1;
|
if (!Utils.isValidShellResponse(ret)) return -1;
|
||||||
@ -128,14 +112,13 @@ public class FlashZIP extends SerialTask<Void, String, Integer> {
|
|||||||
for (String line : ret) {
|
for (String line : ret) {
|
||||||
Logger.dev(line);
|
Logger.dev(line);
|
||||||
}
|
}
|
||||||
Shell.su(
|
if (Boolean.parseBoolean(ret.get(ret.size() - 1)))
|
||||||
"rm -rf " + mCachedFile.getParent() + "/*",
|
return cleanup(1);
|
||||||
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
|
|
||||||
);
|
} catch (Throwable e) {
|
||||||
if (Boolean.parseBoolean(ret.get(ret.size() - 1))) {
|
e.printStackTrace();
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
return -1;
|
return cleanup(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
||||||
@ -146,8 +129,7 @@ public class FlashZIP extends SerialTask<Void, String, Integer> {
|
|||||||
switch (result) {
|
switch (result) {
|
||||||
case -1:
|
case -1:
|
||||||
Toast.makeText(magiskManager, magiskManager.getString(R.string.install_error), Toast.LENGTH_LONG).show();
|
Toast.makeText(magiskManager, magiskManager.getString(R.string.install_error), Toast.LENGTH_LONG).show();
|
||||||
Toast.makeText(magiskManager, magiskManager.getString(R.string.manual_install_1, mUri.getPath()), Toast.LENGTH_LONG).show();
|
Utils.showUriSnack(activity, mUri);
|
||||||
Toast.makeText(magiskManager, magiskManager.getString(R.string.manual_install_2), Toast.LENGTH_LONG).show();
|
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
Toast.makeText(magiskManager, magiskManager.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show();
|
Toast.makeText(magiskManager, magiskManager.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show();
|
||||||
@ -162,7 +144,7 @@ public class FlashZIP extends SerialTask<Void, String, Integer> {
|
|||||||
magiskManager.updateCheckDone.trigger();
|
magiskManager.updateCheckDone.trigger();
|
||||||
new LoadModules(activity).exec();
|
new LoadModules(activity).exec();
|
||||||
|
|
||||||
Utils.getAlertDialogBuilder(activity)
|
new AlertDialogBuilder(activity)
|
||||||
.setTitle(R.string.reboot_title)
|
.setTitle(R.string.reboot_title)
|
||||||
.setMessage(R.string.reboot_msg)
|
.setMessage(R.string.reboot_msg)
|
||||||
.setPositiveButton(R.string.reboot, (dialogInterface, i) -> Shell.su(true, "reboot"))
|
.setPositiveButton(R.string.reboot, (dialogInterface, i) -> Shell.su(true, "reboot"))
|
@ -0,0 +1,93 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class ProcessMagiskZip extends ParallelTask<Void, Void, Boolean> {
|
||||||
|
|
||||||
|
private Uri mUri;
|
||||||
|
private ProgressDialog progressDialog;
|
||||||
|
private String mBoot;
|
||||||
|
private boolean mEnc, mVerity;
|
||||||
|
|
||||||
|
public ProcessMagiskZip(Activity context, Uri uri, String boot, boolean enc, boolean verity) {
|
||||||
|
super(context);
|
||||||
|
mUri = uri;
|
||||||
|
mBoot = boot;
|
||||||
|
mEnc = enc;
|
||||||
|
mVerity = verity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
progressDialog = ProgressDialog.show(activity,
|
||||||
|
activity.getString(R.string.zip_install_progress_title),
|
||||||
|
activity.getString(R.string.zip_install_unzip_zip_msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
if (Shell.rootAccess()) {
|
||||||
|
try {
|
||||||
|
// We might not have busybox yet, unzip with Java
|
||||||
|
// We shall have complete busybox after Magisk installation
|
||||||
|
File tempdir = new File(magiskManager.getCacheDir(), "magisk");
|
||||||
|
ZipUtils.unzip(magiskManager.getContentResolver().openInputStream(mUri), tempdir);
|
||||||
|
// Running in parallel mode, open new shell
|
||||||
|
Shell.su(true,
|
||||||
|
"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,
|
||||||
|
"cp -af " + tempdir + "/. " + MagiskManager.TMP_FOLDER_PATH + "/magisk",
|
||||||
|
"mv -f " + tempdir + "/META-INF " + magiskManager.getCacheDir() + "/META-INF",
|
||||||
|
"rm -rf " + tempdir
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.error("ProcessMagiskZip: Error!");
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
progressDialog.dismiss();
|
||||||
|
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<Void, Void, Void>(activity) {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
Shell.su("setprop magisk.version "
|
||||||
|
+ String.valueOf(magiskManager.remoteMagiskVersion));
|
||||||
|
magiskManager.updateCheckDone.trigger();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.exec();
|
||||||
|
super.onSuccess();
|
||||||
|
}
|
||||||
|
}.exec();
|
||||||
|
else
|
||||||
|
Utils.showUriSnack(activity, mUri);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.utils.ByteArrayInOutStream;
|
||||||
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
|
||||||
|
|
||||||
|
private Uri mUri;
|
||||||
|
private ProgressDialog progressDialog;
|
||||||
|
|
||||||
|
public ProcessRepoZip(Activity context, Uri uri) {
|
||||||
|
super(context);
|
||||||
|
mUri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
progressDialog = ProgressDialog.show(activity,
|
||||||
|
activity.getString(R.string.zip_install_progress_title),
|
||||||
|
activity.getString(R.string.zip_install_process_zip_msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
// Create a buffer in memory for input/output
|
||||||
|
ByteArrayInOutStream buffer = new ByteArrayInOutStream();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// First remove top folder (the folder with the repo name) in Github source zip
|
||||||
|
ZipUtils.removeTopFolder(activity.getContentResolver().openInputStream(mUri), buffer);
|
||||||
|
|
||||||
|
// Then sign the zip for the first time
|
||||||
|
ZipUtils.signZip(activity, buffer.getInputStream(), buffer, false);
|
||||||
|
|
||||||
|
// Adjust the zip to prevent unzip issues
|
||||||
|
ZipUtils.adjustZip(buffer);
|
||||||
|
|
||||||
|
// Finally, sign the whole zip file again
|
||||||
|
ZipUtils.signZip(activity, buffer.getInputStream(), buffer, true);
|
||||||
|
|
||||||
|
// Write it back to the downloaded zip
|
||||||
|
try (OutputStream out = activity.getContentResolver().openOutputStream(mUri)) {
|
||||||
|
buffer.writeTo(out);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.error("ProcessRepoZip: Error!");
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
progressDialog.dismiss();
|
||||||
|
if (result) {
|
||||||
|
if (Shell.rootAccess())
|
||||||
|
new FlashZip(activity, mUri).exec();
|
||||||
|
else
|
||||||
|
Utils.showUriSnack(activity, mUri);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Toast.makeText(activity, R.string.process_error, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class SnackbarMaker {
|
||||||
|
|
||||||
|
public static Snackbar make(Activity activity, CharSequence text, int duration) {
|
||||||
|
View view = activity.findViewById(android.R.id.content);
|
||||||
|
return make(view, text, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Snackbar make(Activity activity, @StringRes int resId, int duration) {
|
||||||
|
return make(activity, activity.getString(resId), duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Snackbar make(View view, CharSequence text, int duration) {
|
||||||
|
Snackbar snack = Snackbar.make(view, text, duration);
|
||||||
|
setup(snack);
|
||||||
|
return snack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Snackbar make(View view, @StringRes int resId, int duration) {
|
||||||
|
Snackbar snack = Snackbar.make(view, resId, duration);
|
||||||
|
setup(snack);
|
||||||
|
return snack;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,68 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.receivers;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
import com.topjohnwu.magisk.asyncs.FlashZIP;
|
|
||||||
import com.topjohnwu.magisk.asyncs.SerialTask;
|
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
|
||||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class MagiskDlReceiver extends DownloadReceiver {
|
|
||||||
|
|
||||||
String mBoot;
|
|
||||||
boolean mEnc, mVerity;
|
|
||||||
|
|
||||||
public MagiskDlReceiver(String bootImage, boolean keepEnc, boolean keepVerity) {
|
|
||||||
mBoot = bootImage;
|
|
||||||
mEnc = keepEnc;
|
|
||||||
mVerity = keepVerity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDownloadDone(Uri uri) {
|
|
||||||
new FlashZIP(activity, uri, mFilename) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void preProcessing() throws Throwable {
|
|
||||||
Shell.su(
|
|
||||||
"echo \"BOOTIMAGE=/dev/block/" + mBoot + "\" > /dev/.magisk",
|
|
||||||
"echo \"KEEPFORCEENCRYPT=" + String.valueOf(mEnc) + "\" >> /dev/.magisk",
|
|
||||||
"echo \"KEEPVERITY=" + String.valueOf(mVerity) + "\" >> /dev/.magisk"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean unzipAndCheck() {
|
|
||||||
publishProgress(activity.getString(R.string.zip_install_unzip_zip_msg));
|
|
||||||
if (Shell.rootAccess()) {
|
|
||||||
// We might not have busybox yet, unzip with Java
|
|
||||||
// We will have complete busybox after Magisk installation
|
|
||||||
ZipUtils.unzip(mCachedFile, new File(mCachedFile.getParent(), "magisk"));
|
|
||||||
Shell.su(
|
|
||||||
"mkdir -p " + MagiskManager.TMP_FOLDER_PATH + "/magisk",
|
|
||||||
"cp -af " + mCachedFile.getParent() + "/magisk/. " + MagiskManager.TMP_FOLDER_PATH + "/magisk",
|
|
||||||
"mv -f " + mCachedFile.getParent() + "/magisk/META-INF " + mCachedFile.getParent() + "/META-INF"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSuccess() {
|
|
||||||
new SerialTask<Void, Void, Void>() {
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... params) {
|
|
||||||
Shell.su("setprop magisk.version "
|
|
||||||
+ String.valueOf(((MagiskManager) activity.getApplicationContext()).remoteMagiskVersion));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}.exec();
|
|
||||||
super.onSuccess();
|
|
||||||
}
|
|
||||||
}.exec();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.receivers;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
import com.topjohnwu.magisk.asyncs.FlashZIP;
|
|
||||||
import com.topjohnwu.magisk.utils.ByteArrayInOutStream;
|
|
||||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public class RepoDlReceiver extends DownloadReceiver {
|
|
||||||
@Override
|
|
||||||
public void onDownloadDone(Uri uri) {
|
|
||||||
// Flash the zip
|
|
||||||
new FlashZIP(activity, uri, mFilename){
|
|
||||||
@Override
|
|
||||||
protected void preProcessing() throws Throwable {
|
|
||||||
// Process and sign the zip
|
|
||||||
publishProgress(activity.getString(R.string.zip_install_process_zip_msg));
|
|
||||||
ByteArrayInOutStream buffer = new ByteArrayInOutStream();
|
|
||||||
|
|
||||||
// First remove top folder (the folder with the repo name) in Github source zip
|
|
||||||
ZipUtils.removeTopFolder(activity.getContentResolver().openInputStream(mUri), buffer);
|
|
||||||
|
|
||||||
// Then sign the zip for the first time
|
|
||||||
ZipUtils.signZip(activity, buffer.getInputStream(), buffer, false);
|
|
||||||
|
|
||||||
// Adjust the zip to prevent unzip issues
|
|
||||||
ZipUtils.adjustZip(buffer);
|
|
||||||
|
|
||||||
// Finally, sign the whole zip file again
|
|
||||||
ZipUtils.signZip(activity, buffer.getInputStream(), buffer, true);
|
|
||||||
|
|
||||||
// Write it back to the downloaded zip
|
|
||||||
try (OutputStream out = activity.getContentResolver().openOutputStream(mUri)) {
|
|
||||||
buffer.writeTo(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.exec();
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,17 +7,19 @@ import android.content.Context;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||||
|
|
||||||
@ -117,15 +119,6 @@ public class Utils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AlertDialog.Builder getAlertDialogBuilder(Context context) {
|
|
||||||
// if (((MagiskManager) context.getApplicationContext()).isDarkTheme) {
|
|
||||||
// return new AlertDialog.Builder(context, R.style.AlertDialog_dh);
|
|
||||||
// } else {
|
|
||||||
// return new AlertDialog.Builder(context);
|
|
||||||
// }
|
|
||||||
return new AlertDialogBuilder(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean lowercaseContains(CharSequence string, CharSequence nonNullLowercaseSearch) {
|
public static boolean lowercaseContains(CharSequence string, CharSequence nonNullLowercaseSearch) {
|
||||||
return !TextUtils.isEmpty(string) && string.toString().toLowerCase().contains(nonNullLowercaseSearch);
|
return !TextUtils.isEmpty(string) && string.toString().toLowerCase().contains(nonNullLowercaseSearch);
|
||||||
}
|
}
|
||||||
@ -164,4 +157,29 @@ public class Utils {
|
|||||||
new RepoDatabaseHelper(activity).clearRepo();
|
new RepoDatabaseHelper(activity).clearRepo();
|
||||||
Toast.makeText(activity, R.string.repo_cache_cleared, Toast.LENGTH_SHORT).show();
|
Toast.makeText(activity, R.string.repo_cache_cleared, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getNameFromUri(Context context, Uri uri) {
|
||||||
|
String name = null;
|
||||||
|
try (Cursor c = context.getContentResolver().query(uri, null, null, null, null)) {
|
||||||
|
if (c != null) {
|
||||||
|
int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||||
|
if (nameIndex != -1) {
|
||||||
|
c.moveToFirst();
|
||||||
|
name = c.getString(nameIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name == null) {
|
||||||
|
int idx = uri.getPath().lastIndexOf('/');
|
||||||
|
name = uri.getPath().substring(idx + 1);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showUriSnack(Activity activity, Uri uri) {
|
||||||
|
SnackbarMaker.make(activity, activity.getString(R.string.internal_storage,
|
||||||
|
"/MagiskManager/" + Utils.getNameFromUri(activity, uri)),
|
||||||
|
Snackbar.LENGTH_LONG)
|
||||||
|
.setAction(R.string.ok, (v)->{}).show();
|
||||||
|
}
|
||||||
}
|
}
|
@ -6,10 +6,12 @@ import android.webkit.WebResourceRequest;
|
|||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
|
|
||||||
public class WebWindow {
|
public class WebWindow {
|
||||||
|
|
||||||
public WebWindow(String title, String url, Context context) {
|
public WebWindow(String title, String url, Context context) {
|
||||||
AlertDialog.Builder alert = Utils.getAlertDialogBuilder(context);
|
AlertDialog.Builder alert = new AlertDialogBuilder(context);
|
||||||
alert.setTitle(title);
|
alert.setTitle(title);
|
||||||
|
|
||||||
Logger.dev("WebView: URL = " + url);
|
Logger.dev("WebView: URL = " + url);
|
||||||
|
@ -48,6 +48,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@ -88,7 +89,7 @@ public class ZipUtils {
|
|||||||
buffer.setBuffer(zipAdjust(buffer.toByteArray(), buffer.size()));
|
buffer.setBuffer(zipAdjust(buffer.toByteArray(), buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeTopFolder(InputStream in, OutputStream out) {
|
public static void removeTopFolder(InputStream in, OutputStream out) throws IOException {
|
||||||
try {
|
try {
|
||||||
JarInputStream source = new JarInputStream(in);
|
JarInputStream source = new JarInputStream(in);
|
||||||
JarOutputStream dest = new JarOutputStream(out);
|
JarOutputStream dest = new JarOutputStream(out);
|
||||||
@ -113,16 +114,20 @@ public class ZipUtils {
|
|||||||
dest.close();
|
dest.close();
|
||||||
in.close();
|
in.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
|
||||||
Logger.dev("ZipUtils: removeTopFolder IO error!");
|
Logger.dev("ZipUtils: removeTopFolder IO error!");
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void unzip(File file, File folder) {
|
public static void unzip(File file, File folder) throws Exception {
|
||||||
unzip(file, folder, "");
|
unzip(file, folder, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void unzip(File file, File folder, String path) {
|
public static void unzip(InputStream file, File folder) throws Exception {
|
||||||
|
unzip(file, folder, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unzip(File file, File folder, String path) throws Exception {
|
||||||
int count;
|
int count;
|
||||||
FileOutputStream out;
|
FileOutputStream out;
|
||||||
File dest;
|
File dest;
|
||||||
@ -133,32 +138,56 @@ public class ZipUtils {
|
|||||||
Enumeration<JarEntry> e = zipfile.entries();
|
Enumeration<JarEntry> e = zipfile.entries();
|
||||||
while(e.hasMoreElements()) {
|
while(e.hasMoreElements()) {
|
||||||
entry = e.nextElement();
|
entry = e.nextElement();
|
||||||
if (!entry.getName().contains(path)
|
if (!entry.getName().contains(path) || entry.isDirectory())
|
||||||
|| entry.getName().charAt(entry.getName().length() - 1) == '/') {
|
|
||||||
// Ignore directories, only create files
|
// Ignore directories, only create files
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
Logger.dev("ZipUtils: Extracting: " + entry);
|
Logger.dev("ZipUtils: Extracting: " + entry);
|
||||||
is = zipfile.getInputStream(entry);
|
is = zipfile.getInputStream(entry);
|
||||||
dest = new File(folder, entry.getName());
|
dest = new File(folder, entry.getName());
|
||||||
if (dest.getParentFile().mkdirs()) {
|
if (dest.getParentFile().mkdirs())
|
||||||
dest.createNewFile();
|
dest.createNewFile();
|
||||||
}
|
|
||||||
out = new FileOutputStream(dest);
|
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.write(data, 0, count);
|
||||||
}
|
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
is.close();
|
is.close();
|
||||||
}
|
}
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unzip(InputStream file, File folder, String path) throws Exception {
|
||||||
|
int count;
|
||||||
|
FileOutputStream out;
|
||||||
|
File dest;
|
||||||
|
JarEntry entry;
|
||||||
|
byte data[] = new byte[4096];
|
||||||
|
try (JarInputStream zipfile = new JarInputStream(file)) {
|
||||||
|
while((entry = zipfile.getNextJarEntry()) != null) {
|
||||||
|
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())
|
||||||
|
dest.createNewFile();
|
||||||
|
out = new FileOutputStream(dest);
|
||||||
|
while ((count = zipfile.read(data, 0, 4096)) != -1)
|
||||||
|
out.write(data, 0, count);
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
} catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void signZip(Context context, InputStream inputStream,
|
public static void signZip(Context context, InputStream inputStream,
|
||||||
OutputStream outputStream, boolean signWholeFile) {
|
OutputStream outputStream, boolean signWholeFile) throws Exception {
|
||||||
JarMap inputJar;
|
JarMap inputJar;
|
||||||
int hashes = 0;
|
int hashes = 0;
|
||||||
try {
|
try {
|
||||||
@ -192,6 +221,7 @@ public class ZipUtils {
|
|||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,6 +257,13 @@ public class ZipUtils {
|
|||||||
public Manifest getManifest() {
|
public Manifest getManifest() {
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
|
public Enumeration<JarEntry> entries() {
|
||||||
|
Iterator<Map.Entry<String, Pair<JarEntry, ByteArrayOutputStream> >> i = entrySet().iterator();
|
||||||
|
ArrayList<JarEntry> list = new ArrayList<>();
|
||||||
|
while (i.hasNext())
|
||||||
|
list.add(i.next().getValue().first);
|
||||||
|
return Collections.enumeration(list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,6 +90,7 @@
|
|||||||
<string name="permissionNotGranted">This feature will not work without permission to write external storage.</string>
|
<string name="permissionNotGranted">This feature will not work without permission to write external storage.</string>
|
||||||
<string name="no_thanks">No thanks</string>
|
<string name="no_thanks">No thanks</string>
|
||||||
<string name="yes">Yes</string>
|
<string name="yes">Yes</string>
|
||||||
|
<string name="ok">OK</string>
|
||||||
<string name="repo_install_title">Install %1$s</string>
|
<string name="repo_install_title">Install %1$s</string>
|
||||||
<string name="repo_install_msg">Do you want to install %1$s ?</string>
|
<string name="repo_install_msg">Do you want to install %1$s ?</string>
|
||||||
<string name="download_install">Download & install</string>
|
<string name="download_install">Download & install</string>
|
||||||
@ -120,6 +121,8 @@
|
|||||||
<string name="no_magisksu_title">Not using MagiskSU!</string>
|
<string name="no_magisksu_title">Not using MagiskSU!</string>
|
||||||
<string name="no_magisksu_msg">You are not rooted with MagiskSU, using MagiskHide itself might not be enough!\nIt\'s not officially supported, and you would need additional tools (e.g suhide) to pass Safety Net.</string>
|
<string name="no_magisksu_msg">You are not rooted with MagiskSU, using MagiskHide itself might not be enough!\nIt\'s not officially supported, and you would need additional tools (e.g suhide) to pass Safety Net.</string>
|
||||||
<string name="understand">I understand</string>
|
<string name="understand">I understand</string>
|
||||||
|
<string name="process_error">Process error</string>
|
||||||
|
<string name="internal_storage">The zip is stored in:\n[Internal Storage]%1$s</string>
|
||||||
|
|
||||||
<!--Settings Activity -->
|
<!--Settings Activity -->
|
||||||
<string name="settings_general_category">General</string>
|
<string name="settings_general_category">General</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user