Ready for release

This commit is contained in:
topjohnwu
2016-09-29 23:24:31 +08:00
parent 692b993eee
commit e4cba70008
30 changed files with 541 additions and 414 deletions

View File

@ -29,7 +29,9 @@ import butterknife.ButterKnife;
public class AboutActivity extends AppCompatActivity {
private static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/MagiskManager";
private static final String XDA_THREAD = "http://forum.xda-developers.com/android/software/mod-magisk-v1-universal-systemless-t3432382";
private static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
private static final String DONATION_URL = "http://topjohnwu.github.io/donate";
private AlertDialog.Builder builder;
@BindView(R.id.toolbar) Toolbar toolbar;
@ -39,6 +41,7 @@ public class AboutActivity extends AppCompatActivity {
@BindView(R.id.app_translators) RowItem appTranslators;
@BindView(R.id.app_source_code) RowItem appSourceCode;
@BindView(R.id.support_thread) RowItem supportThread;
@BindView(R.id.donation) RowItem donation;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -139,6 +142,9 @@ public class AboutActivity extends AppCompatActivity {
supportThread.removeSummary();
supportThread.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(XDA_THREAD))));
donation.removeSummary();
donation.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(DONATION_URL))));
setFloating();
}

View File

@ -90,10 +90,7 @@ public class LogFragment extends Fragment {
reloadErrorLog();
return true;
case R.id.menu_send:
try {
send();
} catch (NullPointerException ignored) {
}
send();
return true;
case R.id.menu_save:
save();
@ -117,11 +114,23 @@ public class LogFragment extends Fragment {
}
private void send() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(save()));
sendIntent.setType("application/html");
startActivity(Intent.createChooser(sendIntent, getResources().getString(R.string.menuSend)));
new SaveLog() {
@Override
protected void onPostExecute(Boolean bool) {
super.onPostExecute(bool);
if (bool) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(targetFile));
sendIntent.setType("application/html");
startActivity(Intent.createChooser(sendIntent, getResources().getString(R.string.menuSend)));
} else {
Toast.makeText(getActivity(), getString(R.string.logs_save_failed), Toast.LENGTH_LONG).show();
}
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
@Override
@ -138,45 +147,66 @@ public class LogFragment extends Fragment {
}
}
@SuppressLint("DefaultLocale")
private File save() {
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
private void save() {
new SaveLog(){
@Override
protected void onPostExecute(Boolean bool) {
super.onPostExecute(bool);
if (bool) {
Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), getString(R.string.logs_save_failed), Toast.LENGTH_LONG).show();
}
}
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Snackbar.make(txtLog, R.string.sdcard_not_writable, Snackbar.LENGTH_LONG).show();
return null;
}
private class SaveLog extends AsyncTask<Void, Void, Boolean> {
Calendar now = Calendar.getInstance();
String filename = String.format(
"magisk_%s_%04d%02d%02d_%02d%02d%02d.log", "error",
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
File targetFile;
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Magisk/");
dir.mkdir();
File targetFile = new File(dir, filename);
List<String> in = Utils.readFile(MAGISK_LOG);
try {
FileWriter out = new FileWriter(targetFile);
for (String line : in) {
out.write(line + "\n");
@SuppressLint("DefaultLocale")
@Override
protected Boolean doInBackground(Void... voids) {
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
}
return false;
}
out.close();
Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG).show();
return targetFile;
} catch (IOException e) {
Toast.makeText(getActivity(), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Toast.LENGTH_LONG).show();
return null;
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return false;
}
Calendar now = Calendar.getInstance();
String filename = String.format(
"magisk_%s_%04d%02d%02d_%02d%02d%02d.log", "error",
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
targetFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/MagiskManager/" + filename);
if ((!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs()) || (targetFile.exists() && !targetFile.delete())) {
return false;
}
List<String> in = Utils.readFile(MAGISK_LOG);
try {
FileWriter out = new FileWriter(targetFile);
for (String line : in) {
out.write(line + "\n");
}
out.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}

View File

@ -152,7 +152,7 @@ public class MagiskFragment extends Fragment {
private void updateUI() {
String theme = PreferenceManager.getDefaultSharedPreferences(getActivity()).getString("theme", "");
if (theme.equals("Dark")) {
builder = new AlertDialog.Builder(getActivity(),R.style.AlertDialog_dh);
builder = new AlertDialog.Builder(getActivity(), R.style.AlertDialog_dh);
} else {
builder = new AlertDialog.Builder(getActivity());
}
@ -190,11 +190,28 @@ public class MagiskFragment extends Fragment {
"Magisk-v" + String.valueOf(remoteMagiskVersion) + ".zip"))
.setNegativeButton(R.string.no_thanks, null)
.show());
} else {
magiskCheckUpdatesContainer.setBackgroundColor(colorOK);
magiskCheckUpdatesIcon.setImageResource(R.drawable.ic_check_circle);
magiskCheckUpdatesStatus.setText(getString(R.string.up_to_date, getString(R.string.magisk)));
magiskCheckUpdatesStatus.setTextColor(colorOK);
magiskUpdateView.setOnClickListener(view -> builder
.setTitle(getString(R.string.repo_install_title, getString(R.string.magisk)))
.setMessage(getString(R.string.repo_install_msg, "Magisk-v" + String.valueOf(remoteMagiskVersion)))
.setCancelable(true)
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.downloadAndReceive(
getActivity(),
new DownloadReceiver() {
@Override
public void task(Uri uri) {
new Async.FlashZIP(mContext, uri).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
},
magiskLink,
"Magisk-v" + String.valueOf(remoteMagiskVersion) + ".zip"))
.setNegativeButton(R.string.no_thanks, null)
.show());
}
if (remoteAppVersionCode > BuildConfig.VERSION_CODE) {

View File

@ -35,12 +35,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
private final Handler mDrawerHandler = new Handler();
private String currentTitle;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.drawer_layout)
DrawerLayout drawer;
@BindView(R.id.nav_view)
NavigationView navigationView;
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.drawer_layout) DrawerLayout drawer;
@BindView(R.id.nav_view) NavigationView navigationView;
@IdRes
private int mSelectedId = R.id.magisk;

View File

@ -67,7 +67,6 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final Module module = mList.get(position);
Log.d("Magisk", "ModulesAdapter: Trying set up bindview from list pos " + position + " and " + module.getName());
if (module.isCache()) {
holder.title.setText("[Cache] " + module.getName());
} else {

View File

@ -61,7 +61,7 @@ public class ModulesFragment extends Fragment {
mSwipeRefreshLayout.setOnRefreshListener(() -> {
recyclerView.setVisibility(View.GONE);
prefs.edit().putBoolean("module_done", false).apply();
new Async.LoadModules(getActivity()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new Async.LoadModules(getActivity()).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
});
if (prefs.getBoolean("module_done", false)) {

View File

@ -4,9 +4,12 @@ import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.util.Log;
@ -39,6 +42,7 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
private final List<Repo> mList;
private View mView;
private Context context;
private AlertDialog.Builder builder;
public ReposAdapter(List<Repo> list) {
mList = list;
@ -49,6 +53,14 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false);
ButterKnife.bind(this, mView);
context = parent.getContext();
String theme = PreferenceManager.getDefaultSharedPreferences(context).getString("theme", "");
if (theme.equals("Dark")) {
builder = new AlertDialog.Builder(context,R.style.AlertDialog_dh);
} else {
builder = new AlertDialog.Builder(context);
}
return new ViewHolder(mView);
}
@ -75,44 +87,51 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
View.OnClickListener listener = view -> {
if (view.getId() == holder.updateImage.getId()) {
Utils.downloadAndReceive(
context,
new DownloadReceiver(repo.getName() + "-" + repo.getVersion()) {
@Override
public void task(Uri uri) {
new Async.FlashZIP(context, uri, mName) {
String fullname = repo.getName() + "-" + repo.getVersion();
builder
.setTitle(context.getString(R.string.repo_install_title, repo.getName()))
.setMessage(context.getString(R.string.repo_install_msg, fullname))
.setCancelable(true)
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.downloadAndReceive(
context,
new DownloadReceiver(fullname) {
@Override
protected void preProcessing() throws Throwable {
super.preProcessing();
new File(mUri.getPath()).delete();
Shell.su(
"cd " + mFile.getParent(),
"mkdir git",
"unzip -o install.zip -d git",
"mv git/* install",
"cd install",
"rm -rf system/placeholder",
"chmod 644 $(find . -type f)",
"chmod 755 $(find . -type d)",
"rm -rf ../install.zip ../git",
"zip -r ../install.zip *",
"rm -rf ../install"
);
public void task(Uri uri) {
new Async.FlashZIP(context, uri, mName) {
@Override
protected void preProcessing() throws Throwable {
super.preProcessing();
new File(mUri.getPath()).delete();
Shell.su(
"cd " + mFile.getParent(),
"mkdir git",
"unzip -o install.zip -d git",
"mv git/* install",
"cd install",
"rm -rf system/placeholder",
"chmod 644 $(find . -type f)",
"chmod 755 $(find . -type d)",
"rm -rf ../install.zip ../git",
"zip -r ../install.zip *",
"rm -rf ../install"
);
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
},
repo.getZipUrl(),
repo.getId().replace(" ", "") + ".zip");
},
repo.getZipUrl(),
repo.getId().replace(" ", "") + ".zip"))
.setNegativeButton(R.string.no_thanks, null)
.show();
}
if ((view.getId() == holder.changeLog.getId()) && (!repo.getLogUrl().equals(""))) {
new WebWindow("Changelog", repo.getLogUrl(), context);
new WebWindow(context.getString(R.string.changelog), repo.getLogUrl(), context);
}
if ((view.getId() == holder.authorLink.getId()) && (!repo.getSupportUrl().equals(""))) {
new WebWindow("Donate", repo.getDonateUrl(), context);
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(repo.getDonateUrl())));
}
if ((view.getId() == holder.supportLink.getId()) && (!repo.getSupportUrl().equals(""))) {
new WebWindow("Support", repo.getSupportUrl(), context);
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(repo.getSupportUrl())));
}
};

View File

@ -89,6 +89,8 @@ public class RootFragment extends Fragment {
ta3.recycle();
autoRootStatus = Utils.autoToggleEnabled(getActivity());
prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
if (autoRootStatus) {
if (!Utils.hasServicePermission(getActivity())) {
autoRootStatus = false;
@ -96,9 +98,18 @@ public class RootFragment extends Fragment {
}
rootToggle.setEnabled(!autoRootStatus);
autoRootToggle.setChecked(autoRootStatus);
new updateUI().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
updateUI();
rootToggle.setOnClickListener(toggle -> Utils.toggleRoot(((CompoundButton) toggle).isChecked(), getActivity()));
rootToggle.setOnClickListener(toggle -> {
new AsyncTask<Boolean, Void, Void>() {
@Override
protected Void doInBackground(Boolean... bools) {
Utils.toggleRoot(bools[0], getActivity());
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, ((CompoundButton) toggle).isChecked());
});
autoRootToggle.setOnClickListener(toggle -> {
if (!Utils.hasServicePermission(getActivity())) {
@ -106,7 +117,7 @@ public class RootFragment extends Fragment {
Toast.makeText(getActivity(), "Please enable accessibility access for Magisk's auto-toggle feature to work.", Toast.LENGTH_LONG).show();
startActivityForResult(intent, 100);
} else {
ToggleAutoRoot(autoRootToggle.isChecked());
toggleAutoRoot(autoRootToggle.isChecked());
}
}
@ -114,19 +125,45 @@ public class RootFragment extends Fragment {
);
selinuxToggle.setOnClickListener(toggle -> {
Shell.su(((CompoundButton) toggle).isChecked() ? "setenforce 1" : "setenforce 0");
new updateUI().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
new AsyncTask<Boolean, Void, Void>() {
@Override
protected Void doInBackground(Boolean... bools) {
Shell.su(bools[0] ? "setenforce 1" : "setenforce 0");
return null;
}
@Override
protected void onPostExecute(Void v) {
super.onPostExecute(v);
updateUI();
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, ((CompoundButton) toggle).isChecked());
});
return view;
}
@Override
public void onResume() {
super.onResume();
getActivity().setTitle(R.string.root);
listener = (pref, key) -> {
if ((key.contains("autoRootEnable")) || (key.equals("root"))) {
Logger.dev("RootFragmnet, keychange detected for " + key);
//new updateUI().execute();
updateUI();
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
updateUI();
}
@Override
public void onDestroy() {
super.onDestroy();
if (null != listener) {
prefs.unregisterOnSharedPreferenceChangeListener(listener);
}
prefs.unregisterOnSharedPreferenceChangeListener(listener);
}
@Override
@ -135,7 +172,7 @@ public class RootFragment extends Fragment {
Log.d("Magisk", "Got result: " + requestCode + " and " + resultCode);
if (requestCode == 100) {
if (Utils.hasServicePermission(getActivity())) {
ToggleAutoRoot(true);
toggleAutoRoot(true);
Snackbar.make(view, getActivity().getString(R.string.auto_toggle) + " has been enabled.", Snackbar.LENGTH_LONG).show();
} else {
@ -146,7 +183,7 @@ public class RootFragment extends Fragment {
}
}
private void ToggleAutoRoot(boolean toggleState) {
private void toggleAutoRoot(boolean toggleState) {
autoRootStatus = toggleState;
Utils.toggleAutoRoot(toggleState, getActivity());
if (toggleState) {
@ -166,155 +203,119 @@ public class RootFragment extends Fragment {
}
@Override
public void onResume() {
super.onResume();
getActivity().setTitle("Root");
prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
listener = (prefs1, key) -> {
private void updateUI() {
autoRootToggle.setChecked(autoRootStatus);
progressBar.setVisibility(View.GONE);
rootStatusView.setVisibility(View.VISIBLE);
safetynetStatusView.setVisibility(View.VISIBLE);
selinuxStatusView.setVisibility(View.VISIBLE);
if ((key.contains("autoRootEnable")) | (key.equals("root"))) {
Logger.dev("RootFragmnet, keychange detected for " + key);
new updateUI().execute();
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
new updateUI().execute();
}
public class updateUI extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
// Make sure static block invoked
Shell.rootAccess();
// Set up Tile on UI Refresh
if (PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean("enable_quicktile", false)) {
Utils.SetupQuickSettingsTile(getActivity());
}
autoRootStatus = Utils.autoToggleEnabled(getActivity());
return null;
if (Shell.rootAccess()) {
rootToggleView.setVisibility(View.VISIBLE);
autoRootToggleView.setVisibility(View.VISIBLE);
selinuxToggleView.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(Void v) {
super.onPostExecute(v);
autoRootToggle.setChecked(autoRootStatus);
progressBar.setVisibility(View.GONE);
rootStatusView.setVisibility(View.VISIBLE);
safetynetStatusView.setVisibility(View.VISIBLE);
selinuxStatusView.setVisibility(View.VISIBLE);
List<String> selinux = Shell.sh("getenforce");
if (Shell.rootAccess()) {
rootToggleView.setVisibility(View.VISIBLE);
autoRootToggleView.setVisibility(View.VISIBLE);
selinuxToggleView.setVisibility(View.VISIBLE);
}
if (selinux.isEmpty()) {
selinuxStatusContainer.setBackgroundColor(colorNeutral);
selinuxStatusIcon.setImageResource(statusUnknown);
List<String> selinux = Shell.sh("getenforce");
selinuxStatus.setText(R.string.selinux_error_info);
selinuxStatus.setTextColor(colorNeutral);
selinuxToggle.setChecked(false);
} else if (selinux.get(0).equals("Enforcing")) {
selinuxStatusContainer.setBackgroundColor(colorOK);
selinuxStatusIcon.setImageResource(statusOK);
if (selinux.isEmpty()) {
selinuxStatusContainer.setBackgroundColor(colorNeutral);
selinuxStatusIcon.setImageResource(statusUnknown);
selinuxStatus.setText(R.string.selinux_enforcing_info);
selinuxStatus.setTextColor(colorOK);
selinuxToggle.setChecked(true);
} else {
selinuxStatusContainer.setBackgroundColor(colorFail);
selinuxStatusIcon.setImageResource(statusError);
selinuxStatus.setText(R.string.selinux_error_info);
selinuxStatus.setTextColor(colorNeutral);
selinuxToggle.setChecked(false);
} else if (selinux.get(0).equals("Enforcing")) {
selinuxStatusContainer.setBackgroundColor(colorOK);
selinuxStatusIcon.setImageResource(statusOK);
selinuxStatus.setText(R.string.selinux_permissive_info);
selinuxStatus.setTextColor(colorFail);
selinuxToggle.setChecked(false);
}
selinuxStatus.setText(R.string.selinux_enforcing_info);
selinuxStatus.setTextColor(colorOK);
selinuxToggle.setChecked(true);
} else {
selinuxStatusContainer.setBackgroundColor(colorFail);
selinuxStatusIcon.setImageResource(statusError);
if (new File("/system/framework/twframework.jar").exists()) {
selinuxStatus.append("\n" + getString(R.string.selinux_samsung_info));
}
selinuxStatus.setText(R.string.selinux_permissive_info);
selinuxStatus.setTextColor(colorFail);
selinuxToggle.setChecked(false);
}
if (new File("/system/framework/twframework.jar").exists()) {
selinuxStatus.append("\n" + getString(R.string.selinux_samsung_info));
}
switch (Shell.rootStatus) {
case -1:
// Root Error
rootStatusContainer.setBackgroundColor(colorFail);
rootStatusIcon.setImageResource(statusUnknown);
rootStatus.setTextColor(colorNeutral);
rootStatus.setText(R.string.root_error);
rootToggle.setChecked(false);
safetyNetStatusIcon.setImageResource(statusUnknown);
safetyNetStatus.setText(R.string.root_error_info);
break;
case 0:
// Not rooted
switch (Shell.rootStatus) {
case -1:
// Root Error
rootStatusContainer.setBackgroundColor(colorFail);
rootStatusIcon.setImageResource(statusUnknown);
rootStatus.setTextColor(colorNeutral);
rootStatus.setText(R.string.root_error);
rootToggle.setChecked(false);
safetyNetStatusIcon.setImageResource(statusUnknown);
safetyNetStatus.setText(R.string.root_error_info);
break;
case 0:
// Not rooted
rootStatusContainer.setBackgroundColor(colorOK);
rootStatusIcon.setImageResource(statusOK);
rootStatus.setTextColor(colorOK);
rootStatus.setText(R.string.root_none);
rootToggle.setChecked(false);
safetyNetStatusIcon.setImageResource(statusOK);
safetyNetStatus.setText(R.string.root_none_info);
break;
case 1:
// Proper root
if (autoRootStatus) {
rootStatusContainer.setBackgroundColor(colorOK);
rootStatusIcon.setImageResource(statusOK);
rootStatusIcon.setImageResource(statusAuto);
rootStatusIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
rootStatus.setTextColor(colorOK);
rootStatus.setText(R.string.root_none);
rootToggle.setChecked(false);
rootStatus.setText(R.string.root_auto_unmounted);
rootToggle.setEnabled(false);
autoRootToggle.setChecked(true);
safetyNetStatusIcon.setImageResource(statusOK);
safetyNetStatus.setText(R.string.root_none_info);
safetyNetStatus.setText(R.string.root_auto_unmounted_info);
break;
case 1:
// Proper root
if (autoRootStatus) {
rootStatusContainer.setBackgroundColor(colorOK);
rootStatusIcon.setImageResource(statusAuto);
rootStatusIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
rootStatus.setTextColor(colorOK);
rootStatus.setText(R.string.root_auto_unmounted);
rootToggle.setEnabled(false);
autoRootToggle.setChecked(true);
safetyNetStatusIcon.setImageResource(statusOK);
safetyNetStatus.setText(R.string.root_auto_unmounted_info);
} else {
rootToggle.setEnabled(true);
if (Utils.rootEnabled()) {
// Mounted
rootStatusContainer.setBackgroundColor(colorWarn);
rootStatusIcon.setImageResource(statusError);
rootStatus.setTextColor(colorWarn);
rootStatus.setText(R.string.root_enabled);
rootToggle.setChecked(true);
safetyNetStatusIcon.setImageResource(statusError);
safetyNetStatus.setText(R.string.root_enabled_info);
break;
} else {
rootToggle.setEnabled(true);
if (Utils.rootEnabled()) {
// Mounted
rootStatusContainer.setBackgroundColor(colorWarn);
rootStatusIcon.setImageResource(statusError);
rootStatus.setTextColor(colorWarn);
rootStatus.setText(R.string.root_enabled);
rootToggle.setChecked(true);
safetyNetStatusIcon.setImageResource(statusError);
safetyNetStatus.setText(R.string.root_enabled_info);
break;
} else {
// Disabled
rootStatusContainer.setBackgroundColor(colorOK);
rootStatusIcon.setImageResource(statusOK);
rootStatus.setTextColor(colorOK);
rootStatus.setText(R.string.root_disabled);
rootToggle.setChecked(false);
safetyNetStatusIcon.setImageResource(statusOK);
safetyNetStatus.setText(R.string.root_disabled_info);
break;
}
// Disabled
rootStatusContainer.setBackgroundColor(colorOK);
rootStatusIcon.setImageResource(statusOK);
rootStatus.setTextColor(colorOK);
rootStatus.setText(R.string.root_disabled);
rootToggle.setChecked(false);
safetyNetStatusIcon.setImageResource(statusOK);
safetyNetStatus.setText(R.string.root_disabled_info);
break;
}
case 2:
// Improper root
rootStatusContainer.setBackgroundColor(colorFail);
rootStatusIcon.setImageResource(statusError);
rootStatus.setTextColor(colorFail);
rootStatus.setText(R.string.root_system);
rootToggle.setChecked(true);
safetyNetStatusIcon.setImageResource(statusError);
safetyNetStatus.setText(R.string.root_system_info);
autoRootToggleView.setVisibility(View.GONE);
rootToggleView.setVisibility(View.GONE);
selinuxToggleView.setVisibility(View.GONE);
break;
}
}
case 2:
// Improper root
rootStatusContainer.setBackgroundColor(colorFail);
rootStatusIcon.setImageResource(statusError);
rootStatus.setTextColor(colorFail);
rootStatus.setText(R.string.root_system);
rootToggle.setChecked(true);
safetyNetStatusIcon.setImageResource(statusError);
safetyNetStatus.setText(R.string.root_system_info);
autoRootToggleView.setVisibility(View.GONE);
rootToggleView.setVisibility(View.GONE);
selinuxToggleView.setVisibility(View.GONE);
break;
}
}

View File

@ -2,6 +2,7 @@ package com.topjohnwu.magisk;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
@ -12,19 +13,18 @@ import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Utils;
import butterknife.ButterKnife;
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
private CheckBoxPreference quickTilePreference;
private CheckBoxPreference quickTilePreference, busyboxPreference;
private ListPreference themePreference;
public SettingsFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -50,9 +50,10 @@ public class SettingsFragment extends PreferenceFragment implements SharedPrefer
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
ButterKnife.bind(this, view);
quickTilePreference = (CheckBoxPreference) findPreference("enable_quicktile");
themePreference = (ListPreference) findPreference("theme");
busyboxPreference = (CheckBoxPreference) findPreference("busybox");
quickTilePreference = (CheckBoxPreference) findPreference("enable_quicktile") ;
busyboxPreference.setChecked(Utils.commandExists("unzip"));
PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(this);
CheckBoxPreference keepRootOffPreference = (CheckBoxPreference) findPreference("keep_root_off");
CheckBoxPreference hideRootNotificationPreference = (CheckBoxPreference) findPreference("hide_root_notification");
@ -67,21 +68,6 @@ public class SettingsFragment extends PreferenceFragment implements SharedPrefer
hideRootNotificationPreference.setEnabled(true);
}
Preference.OnPreferenceClickListener preferenceClickListener = preference -> {
if (preference == quickTilePreference) {
boolean isChecked = quickTilePreference.isChecked();
if (isChecked) {
Utils.installTile(getActivity());
} else {
Utils.uninstallTile(getActivity());
}
}
return false;
};
quickTilePreference.setOnPreferenceClickListener(preferenceClickListener);
// calculate margins
int horizontalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
int verticalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
@ -118,6 +104,44 @@ public class SettingsFragment extends PreferenceFragment implements SharedPrefer
Logger.dev("SettingsFragment: theme is " + pref);
} else if (key.equals("enable_quicktile")) {
boolean checked = sharedPreferences.getBoolean("enable_quicktile", false);
if (checked) {
new AsyncTask<Void, Void, Boolean> () {
@Override
protected Boolean doInBackground(Void... voids) {
return Utils.installTile(getActivity());
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result) {
Toast.makeText(getActivity(), "Tile installed", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "Tile installation error", Toast.LENGTH_SHORT).show();
}
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
} else {
new AsyncTask<Void, Void, Boolean> () {
@Override
protected Boolean doInBackground(Void... voids) {
return Utils.uninstallTile(getActivity());
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result) {
Toast.makeText(getActivity(), "Tile uninstalled", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "Tile uninstallation error", Toast.LENGTH_SHORT).show();
}
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
} else if (key.equals("busybox")) {
boolean checked = sharedPreferences.getBoolean("busybox", false);
new Async.LinkBusyBox(checked).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
}

View File

@ -19,7 +19,6 @@ public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences defaultPrefs = PreferenceManager.getDefaultSharedPreferences(getApplication());
if (defaultPrefs.getString("theme","").equals("Dark")) {
@ -35,8 +34,8 @@ public class SplashActivity extends AppCompatActivity {
set.add("com.google.android.gms");
set.add("com.google.commerce.tapandpay");
editor.putStringSet("auto_blacklist", set);
editor.putBoolean("autoRootEnable",false);
editor.putBoolean("root",Utils.rootEnabled());
editor.putBoolean("autoRootEnable", false);
editor.putBoolean("root", Utils.rootEnabled());
editor.apply();
}
@ -56,7 +55,7 @@ public class SplashActivity extends AppCompatActivity {
}
// Set up quick settings tile
Utils.SetupQuickSettingsTile(getApplicationContext());
Utils.setupQuickSettingsTile(getApplicationContext());
// Initialize
Utils.init(this);

View File

@ -1,5 +1,7 @@
package com.topjohnwu.magisk.module;
import android.os.AsyncTask;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.ModuleHelper;
import com.topjohnwu.magisk.utils.Utils;
@ -34,11 +36,23 @@ public class Module extends BaseModule {
}
public void createDisableFile() {
mEnable = !Utils.createFile(mDisableFile);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
mEnable = !Utils.createFile(mDisableFile);
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
public void removeDisableFile() {
mEnable = Utils.removeFile(mDisableFile);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
mEnable = Utils.removeFile(mDisableFile);
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
public boolean isEnabled() {
@ -46,11 +60,23 @@ public class Module extends BaseModule {
}
public void createRemoveFile() {
mRemove = Utils.createFile(mRemoveFile);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
mRemove = Utils.createFile(mRemoveFile);
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
public void deleteRemoveFile() {
mRemove = !Utils.removeFile(mRemoveFile);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
mRemove = !Utils.removeFile(mRemoveFile);
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
public boolean willBeRemoved() {

View File

@ -19,7 +19,7 @@ public class AutoStartReceiver extends BroadcastReceiver {
Utils.toggleRoot(false, context);
}
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("enable_quicktile", false)) {
Utils.SetupQuickSettingsTile(context);
Utils.setupQuickSettingsTile(context);
}

View File

@ -32,6 +32,6 @@ public final class PrivateBroadcastReceiver extends BroadcastReceiver {
Utils.toggleRoot(false, context);
}
Utils.SetupQuickSettingsTile(context);
Utils.setupQuickSettingsTile(context);
}
}

View File

@ -46,16 +46,18 @@ public class Async {
String busybox = mContext.getApplicationInfo().dataDir + "/lib/libbusybox.so";
String zip = mContext.getApplicationInfo().dataDir + "/lib/libzip.so";
if (Shell.rootAccess()) {
if (!Utils.commandExists("unzip") || !Utils.commandExists("zip") || !Utils.itemExist(toolPath)) {
if (!Utils.itemExist(toolPath)) {
Shell.sh(
"rm -rf " + toolPath,
"mkdir " + toolPath,
"chmod 755 " + toolPath,
"ln -s " + busybox + " " + toolPath + "/busybox",
"for tool in $(" + toolPath + "/busybox --list); do",
"ln -s " + busybox + " " + toolPath + "/$tool",
"cd " + toolPath,
"ln -s " + busybox + " busybox",
"for tool in $(./busybox --list); do",
"ln -s " + busybox + " $tool",
"done",
"ln -s " + zip + " " + toolPath + "/zip"
"rm -f su sh",
"ln -s " + zip + " zip"
);
}
}
@ -165,15 +167,18 @@ public class Async {
mContext = context;
mUri = uri;
Cursor c = mContext.getContentResolver().query(uri, null, null, null, null);
int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME);
c.moveToFirst();
if (nameIndex != -1) {
mName = c.getString(nameIndex);
} else {
if (c != null) {
int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME);
c.moveToFirst();
if (nameIndex != -1) {
mName = c.getString(nameIndex);
}
c.close();
}
if (mName == null) {
int idx = uri.getPath().lastIndexOf('/');
mName = uri.getPath().substring(idx + 1);
}
c.close();
copyToSD = false;
}
@ -296,6 +301,10 @@ public class Async {
}
protected void done() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
prefs.edit().putBoolean("module_done", false).apply();
new LoadModules(mContext).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
AlertDialog.Builder builder;
String theme = PreferenceManager.getDefaultSharedPreferences(mContext).getString("theme", "");
if (theme.equals("Dark")) {
@ -306,9 +315,31 @@ public class Async {
builder
.setTitle(R.string.reboot_title)
.setMessage(R.string.reboot_msg)
.setPositiveButton(R.string.reboot, (dialogInterface1, i) -> Shell.su("sh -c reboot"))
.setPositiveButton(R.string.reboot, (dialogInterface1, i) -> Shell.sh("su -c reboot"))
.setNegativeButton(R.string.no_thanks, null)
.show();
}
}
public static class LinkBusyBox extends AsyncTask<Void, Void, Void> {
private boolean link;
public LinkBusyBox(boolean b) {
link = b;
}
@Override
protected Void doInBackground(Void... voids) {
if (link) {
Shell.su(
"rm -rf /magisk/.core/busybox",
"ln -s /data/busybox /magisk/.core/busybox"
);
} else {
Shell.su("rm -rf /magisk/.core/busybox");
}
return null;
}
}
}

View File

@ -23,7 +23,6 @@ import android.widget.Toast;
import com.kcoppock.broadcasttilesupport.BroadcastTileIntentBuilder;
import com.topjohnwu.magisk.MagiskFragment;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.module.BaseModule;
import com.topjohnwu.magisk.receivers.DownloadReceiver;
import com.topjohnwu.magisk.receivers.PrivateBroadcastReceiver;
import com.topjohnwu.magisk.services.MonitorService;
@ -36,7 +35,6 @@ import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
@ -63,7 +61,7 @@ public class Utils {
MagiskFragment.magiskVersion = Integer.parseInt(ret.get(0));
}
String toolPath = context.getApplicationInfo().dataDir + "/tools";
Shell.su("PATH=$PATH:" + toolPath);
Shell.su("PATH=" + toolPath + ":$PATH");
}
public static boolean itemExist(String path) {
@ -113,7 +111,7 @@ public class Utils {
Shell.su("rm -rf /magisk/.core/bin", "setprop magisk.root 0");
}
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("enable_quicktile", false)) {
SetupQuickSettingsTile(context);
setupQuickSettingsTile(context);
}
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("root", b).apply();
}
@ -140,7 +138,7 @@ public class Utils {
}
}
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("enable_quicktile", false)) {
SetupQuickSettingsTile(context);
setupQuickSettingsTile(context);
}
}
@ -174,7 +172,7 @@ public class Utils {
}
if ((!file.getParentFile().exists() && !file.getParentFile().mkdirs()) || (file.exists() && !file.delete())) {
Toast.makeText(context, R.string.toast_error_makedir, Toast.LENGTH_LONG).show();
Toast.makeText(context, R.string.permissionNotGranted, Toast.LENGTH_LONG).show();
}
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
@ -208,7 +206,7 @@ public class Utils {
return secret;
}
public static void SetupQuickSettingsTile(Context mContext) {
public static void setupQuickSettingsTile(Context mContext) {
Logger.dev("Utils: SetupQuickSettings called");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Logger.dev("Utils: Starting N quick settings service");
@ -266,7 +264,7 @@ public class Utils {
}
}
public static void installTile(Context context) {
public static boolean installTile(Context context) {
String qsTileId;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
qsTileId = "custom(com.topjohnwu.magisk/.services.TileServiceNewApi)";
@ -281,8 +279,7 @@ public class Utils {
if (tiles.size() > 1) {
for (String tile : tiles) {
if (tile.equals(qsTileId)) {
Toast.makeText(context, "Tile already installed", Toast.LENGTH_SHORT).show();
return;
return true;
}
}
@ -290,17 +287,16 @@ public class Utils {
String newTiles = TextUtils.join(",", tiles);
Logger.dev("Utils: NewtilesString is " + newTiles);
Shell.su("settings put secure sysui_qs_tiles \"" + newTiles + "\"");
Toast.makeText(context, "Tile installed", Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
Utils.refreshService(context);
}
return;
return true;
}
}
Toast.makeText(context, "Tile installation error", Toast.LENGTH_SHORT).show();
return false;
}
public static void uninstallTile(Context context) {
public static boolean uninstallTile(Context context) {
String qsTileId;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
@ -323,17 +319,15 @@ public class Utils {
if (isPresent) {
String newTiles = TextUtils.join(",", tiles);
Shell.su("settings put secure sysui_qs_tiles \"" + newTiles + "\"");
Toast.makeText(context, "Tile uninstalled", Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
Utils.refreshService(context);
}
return;
}
Toast.makeText(context, "Tile already uninstalled", Toast.LENGTH_SHORT).show();
return true;
}
}
Toast.makeText(context, "Tile uninstallation error", Toast.LENGTH_SHORT).show();
return false;
}
private static void refreshService(Context context) {