diff --git a/app/build.gradle b/app/build.gradle index 1ac0a3f09..121cec471 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,6 @@ android { } buildTypes { release { - minifyEnabled true - shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } diff --git a/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java index acb96537e..59542e177 100644 --- a/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java @@ -48,12 +48,7 @@ public class AboutActivity extends AppCompatActivity { ButterKnife.bind(this); setSupportActionBar(toolbar); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - finish(); - } - }); + toolbar.setNavigationOnClickListener(view -> finish()); ActionBar ab = getSupportActionBar(); if (ab != null) { @@ -81,37 +76,31 @@ public class AboutActivity extends AppCompatActivity { appChangelog.setVisibility(View.GONE); } else { final String finalChanges = changes; - appChangelog.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - AlertDialog d = new AlertDialog.Builder(AboutActivity.this) - .setTitle(R.string.app_changelog) - .setMessage(Html.fromHtml(finalChanges)) - .setPositiveButton(android.R.string.ok, null) - .create(); - - d.show(); - - //noinspection ConstantConditions - ((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); - } - }); - } - - appDevelopers.removeSummary(); - appDevelopers.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { + appChangelog.setOnClickListener(v -> { AlertDialog d = new AlertDialog.Builder(AboutActivity.this) - .setTitle(R.string.app_developers) - .setMessage(Html.fromHtml(getString(R.string.app_developers_))) + .setTitle(R.string.app_changelog) + .setMessage(Html.fromHtml(finalChanges)) .setPositiveButton(android.R.string.ok, null) .create(); d.show(); + //noinspection ConstantConditions ((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); - } + }); + } + + appDevelopers.removeSummary(); + appDevelopers.setOnClickListener(view -> { + AlertDialog d = new AlertDialog.Builder(AboutActivity.this) + .setTitle(R.string.app_developers) + .setMessage(Html.fromHtml(getString(R.string.app_developers_))) + .setPositiveButton(android.R.string.ok, null) + .create(); + + d.show(); + //noinspection ConstantConditions + ((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); }); String translators = getString(R.string.translators); @@ -122,20 +111,10 @@ public class AboutActivity extends AppCompatActivity { } appSourceCode.removeSummary(); - appSourceCode.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(SOURCE_CODE_URL))); - } - }); + appSourceCode.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(SOURCE_CODE_URL)))); supportThread.removeSummary(); - supportThread.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(XDA_THREAD))); - } - }); + supportThread.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(XDA_THREAD)))); setFloating(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index e7825c36d..9a01bfa7f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -12,8 +12,7 @@ import android.widget.CheckBox; import android.widget.TextView; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.rv.ItemClickListener; -import com.topjohnwu.magisk.rv.ModulesAdapter; +import com.topjohnwu.magisk.utils.Utils; import java.util.List; @@ -38,36 +37,27 @@ public abstract class BaseModuleFragment extends Fragment { return view; } - recyclerView.setAdapter(new ModulesAdapter(listModules(), new ItemClickListener() { - @Override - public void onItemClick(View view, int position) { - // On Checkbox change listener - CheckBox chbox = (CheckBox) view; + recyclerView.setAdapter(new ModulesAdapter(listModules(), (chk, position) -> { + // On Checkbox change listener + CheckBox chbox = (CheckBox) chk; - if (!chbox.isChecked()) { - listModules().get(position).createDisableFile(); - Snackbar.make(view, R.string.disable_file_created, Snackbar.LENGTH_SHORT).show(); - } else { - listModules().get(position).removeDisableFile(); - Snackbar.make(view, R.string.disable_file_removed, Snackbar.LENGTH_SHORT).show(); - } + if (!chbox.isChecked()) { + listModules().get(position).createDisableFile(); + Snackbar.make(chk, R.string.disable_file_created, Snackbar.LENGTH_SHORT).show(); + } else { + listModules().get(position).removeDisableFile(); + Snackbar.make(chk, R.string.disable_file_removed, Snackbar.LENGTH_SHORT).show(); } - }, new ItemClickListener() { - @Override - public void onItemClick(View view, int position) { - // On delete button click listener + }, (deleteBtn, position) -> { + // On delete button click listener - listModules().get(position).createRemoveFile(); - Snackbar.make(view, R.string.remove_file_created, Snackbar.LENGTH_SHORT).show(); - } - }, new ItemClickListener() { - @Override - public void onItemClick(View view, int position) { - // On undelete button click listener + listModules().get(position).createRemoveFile(); + Snackbar.make(deleteBtn, R.string.remove_file_created, Snackbar.LENGTH_SHORT).show(); + }, (undeleteBtn, position) -> { + // On undelete button click listener - listModules().get(position).deleteRemoveFile(); - Snackbar.make(view, R.string.remove_file_deleted, Snackbar.LENGTH_SHORT).show(); - } + listModules().get(position).deleteRemoveFile(); + Snackbar.make(undeleteBtn, R.string.remove_file_deleted, Snackbar.LENGTH_SHORT).show(); })); return view; } diff --git a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java index 3bf3f6e25..56abc16f2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java @@ -101,18 +101,8 @@ public class LogFragment extends Fragment { private void reloadErrorLog() { new LogsManager(true).execute(); - svLog.post(new Runnable() { - @Override - public void run() { - svLog.scrollTo(0, txtLog.getHeight()); - } - }); - hsvLog.post(new Runnable() { - @Override - public void run() { - hsvLog.scrollTo(0, 0); - } - }); + svLog.post(() -> svLog.scrollTo(0, txtLog.getHeight())); + hsvLog.post(() -> hsvLog.scrollTo(0, 0)); } private void clear() { @@ -134,12 +124,7 @@ public class LogFragment extends Fragment { if (requestCode == 0) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (mClickedMenuItem != null) { - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - onOptionsItemSelected(mClickedMenuItem); - } - }, 500); + new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500); } } else { Snackbar.make(txtLog, R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show(); diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java index 0af73c1b6..b22190f0a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java @@ -1,17 +1,9 @@ package com.topjohnwu.magisk; -import android.Manifest; -import android.app.DownloadManager; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Environment; import android.support.annotation.Nullable; -import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v4.content.FileProvider; import android.support.v7.app.AlertDialog; @@ -22,24 +14,10 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; -import android.widget.Toast; -import com.topjohnwu.magisk.receivers.ApkReceiver; -import com.topjohnwu.magisk.receivers.DownloadReceiver; -import com.topjohnwu.magisk.receivers.ZipReceiver; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.List; import butterknife.BindColor; import butterknife.BindView; @@ -47,8 +25,6 @@ import butterknife.ButterKnife; public class MagiskFragment extends Fragment { - private static final String JSON_UPDATE_CHECK = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json"; - @BindView(R.id.progressBarVersion) ProgressBar progressBar; @BindView(R.id.magiskStatusView) View magiskStatusView; @@ -76,10 +52,6 @@ public class MagiskFragment extends Fragment { int statusOK = R.drawable.ic_check_circle; int statusUnknown = R.drawable.ic_help; - private String mLastLink, mLastFile; - private boolean mLastIsApp; - private List version; - @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -87,49 +59,14 @@ public class MagiskFragment extends Fragment { ButterKnife.bind(this, v); new updateUI().execute(); - new CheckUpdates().execute(); return v; } - private void setListener(View clickView, DownloadReceiver receiver, String link, String msg, String file) { - clickView.setOnClickListener(view -> new AlertDialog.Builder(getContext()) - .setTitle(R.string.update_available) - .setMessage(Html.fromHtml(msg)) - .setCancelable(false) - .setPositiveButton(R.string.download, (dialogInterface, i) -> { - - if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(getContext(), R.string.permissionNotGranted, Toast.LENGTH_LONG).show(); - return; - } - - File downloadFile, dir = new File(Environment.getExternalStorageDirectory() + "/MagiskManager"); - - downloadFile = new File(dir + "/" + file); - - if (!dir.exists()) dir.mkdir(); - - DownloadManager downloadManager = (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE); - DownloadManager.Request request = new DownloadManager.Request(Uri.parse(link)); - request.setDestinationUri(Uri.fromFile(downloadFile)); - - if (downloadFile.exists()) downloadFile.delete(); - - receiver.setDownloadID(downloadManager.enqueue(request)); - - getActivity().registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); - }) - .setNegativeButton(R.string.no_thanks, null) - .show()); - } - private class updateUI extends AsyncTask { @Override protected Void doInBackground(Void... voids) { - // Make sure static block invoked - Shell.rootAccess(); return null; } @@ -137,7 +74,7 @@ public class MagiskFragment extends Fragment { protected void onPostExecute(Void v) { super.onPostExecute(v); - if (Shell.magiskVersion == -1) { + if (Utils.magiskVersion == -1) { magiskStatusContainer.setBackgroundColor(grey500); magiskStatusIcon.setImageResource(statusUnknown); @@ -148,46 +85,10 @@ public class MagiskFragment extends Fragment { magiskStatusIcon.setImageResource(statusOK); magiskVersion.setTextColor(green500); - magiskVersion.setText(getString(R.string.magisk_version, String.valueOf(Shell.magiskVersion))); + magiskVersion.setText(getString(R.string.magisk_version, String.valueOf(Utils.magiskVersion))); } - progressBar.setVisibility(View.GONE); - magiskStatusView.setVisibility(View.VISIBLE); - } - } - - private class CheckUpdates extends AsyncTask { - - @Override - protected String doInBackground(Void... voids) { - try { - HttpURLConnection c = (HttpURLConnection) new URL(JSON_UPDATE_CHECK).openConnection(); - c.setRequestMethod("GET"); - c.setInstanceFollowRedirects(false); - c.setDoOutput(false); - c.connect(); - - BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = br.readLine()) != null) { - sb.append(line); - } - br.close(); - return sb.toString(); - } catch (IOException e) { - return null; - } - } - - @Override - protected void onPostExecute(String result) { - super.onPostExecute(result); - - appCheckUpdatesProgress.setVisibility(View.GONE); - magiskCheckUpdatesProgress.setVisibility(View.GONE); - - if (result == null) { + if (Utils.remoteMagiskVersion == -1) { appCheckUpdatesContainer.setBackgroundColor(accent); magiskCheckUpdatesContainer.setBackgroundColor(accent); @@ -196,59 +97,68 @@ public class MagiskFragment extends Fragment { appCheckUpdatesStatus.setText(R.string.cannot_check_updates); magiskCheckUpdatesStatus.setText(R.string.cannot_check_updates); - return; - } - - magiskUpdateView.setVisibility(View.VISIBLE); - appUpdateView.setVisibility(View.VISIBLE); - - try { - JSONObject json = new JSONObject(result); - - JSONObject app = json.getJSONObject("app"); - JSONObject magisk = json.getJSONObject("magisk"); - - String appVersionCode = app.getString("versionCode"); - String appLink = app.getString("link"); - String appChangelog = app.getString("changelog"); - - String magiskVersionCode = magisk.getString("versionCode"); - String magiskLink = magisk.getString("link"); - String magiskChangelog = magisk.getString("changelog"); - - //if (Integer.parseInt(magiskVersionCode) > versionInt) { - if (99 > Shell.magiskVersion) { + } else { + if (Utils.remoteMagiskVersion > Utils.magiskVersion) { magiskCheckUpdatesContainer.setBackgroundColor(blue500); magiskCheckUpdatesIcon.setImageResource(R.drawable.ic_file_download); - magiskCheckUpdatesStatus.setText(getString(R.string.magisk_update_available, magiskVersionCode)); - setListener(magiskUpdateView, new ZipReceiver(), "https://www.dropbox.com/s/dc16jf1ifhv6ef4/Magisk-v7.zip?dl=1", - getString(R.string.update_available_message, "Magisk", appVersionCode, magiskChangelog), - "latest_magisk.zip" - ); + magiskCheckUpdatesStatus.setText(getString(R.string.magisk_update_available, String.valueOf(Utils.remoteMagiskVersion))); + magiskUpdateView.setOnClickListener(view -> new AlertDialog.Builder(getActivity()) + .setTitle(getString(R.string.update_title, getString(R.string.magisk))) + .setMessage(Html.fromHtml(getString(R.string.update_msg, getString(R.string.magisk), String.valueOf(Utils.remoteMagiskVersion), Utils.magiskChangelog))) + .setCancelable(true) + .setPositiveButton(R.string.download_install, (dialogInterface, i) -> { + Utils.downloadAndReceive( + getActivity(), + new Utils.DownloadReceiver(getString(R.string.magisk)) { + @Override + public void task(File file) { + new Utils.FlashZIP(mContext, mName, file.getPath()).execute(); + } + }, + Utils.magiskLink, "latest_magisk.zip"); + }) + .setNegativeButton(R.string.no_thanks, null) + .show()); } else { magiskCheckUpdatesContainer.setBackgroundColor(green500); magiskCheckUpdatesIcon.setImageResource(R.drawable.ic_check_circle); magiskCheckUpdatesStatus.setText(getString(R.string.up_to_date, getString(R.string.magisk))); } - if (Integer.parseInt(appVersionCode) > BuildConfig.VERSION_CODE) { + if (Utils.remoteAppVersion > BuildConfig.VERSION_CODE) { appCheckUpdatesContainer.setBackgroundColor(blue500); appCheckUpdatesIcon.setImageResource(R.drawable.ic_file_download); - appCheckUpdatesStatus.setText(getString(R.string.app_update_available, appVersionCode)); - setListener(appUpdateView, new ApkReceiver(), appLink, - getString(R.string.update_available_message, "Magisk Manager", appVersionCode, appChangelog), - "latest_manager.apk" + appCheckUpdatesStatus.setText(getString(R.string.app_update_available, String.valueOf(Utils.remoteAppVersion))); + appUpdateView.setOnClickListener(view -> new AlertDialog.Builder(getActivity()) + .setTitle(getString(R.string.update_title, getString(R.string.app_name))) + .setMessage(Html.fromHtml(getString(R.string.update_msg, getString(R.string.app_name), String.valueOf(Utils.remoteAppVersion), Utils.appChangelog))) + .setCancelable(true) + .setPositiveButton(R.string.download_install, (dialogInterface, i) -> { + Utils.downloadAndReceive(getActivity(), + new Utils.DownloadReceiver() { + @Override + public void task(File file) { + Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE); + install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + install.setData(FileProvider.getUriForFile(mContext, "com.topjohnwu.magisk.provider", file)); + mContext.startActivity(install); + } + }, + Utils.appLink, "latest_manager.apk"); + }) + .setNegativeButton(R.string.no_thanks, null) + .show() ); - } else { appCheckUpdatesContainer.setBackgroundColor(green500); appCheckUpdatesIcon.setImageResource(R.drawable.ic_check_circle); appCheckUpdatesStatus.setText(getString(R.string.up_to_date, getString(R.string.app_name))); } - - - } catch (JSONException ignored) { } + + progressBar.setVisibility(View.GONE); + appCheckUpdatesProgress.setVisibility(View.GONE); + magiskCheckUpdatesProgress.setVisibility(View.GONE); } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/rv/ModulesAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java similarity index 68% rename from app/src/main/java/com/topjohnwu/magisk/rv/ModulesAdapter.java rename to app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java index 76245bab0..f5cf729f1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/rv/ModulesAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java @@ -1,4 +1,4 @@ -package com.topjohnwu.magisk.rv; +package com.topjohnwu.magisk; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -9,7 +9,6 @@ import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TextView; -import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; @@ -22,11 +21,11 @@ import butterknife.ButterKnife; public class ModulesAdapter extends RecyclerView.Adapter { private final List mList; - private final ItemClickListener chboxListener; - private final ItemClickListener deleteBtnListener; - private final ItemClickListener unDeleteBtnListener; + private final Utils.ItemClickListener chboxListener; + private final Utils.ItemClickListener deleteBtnListener; + private final Utils.ItemClickListener unDeleteBtnListener; - public ModulesAdapter(List list, ItemClickListener chboxListener, ItemClickListener deleteBtnListener, ItemClickListener undeleteBtnListener) { + public ModulesAdapter(List list, Utils.ItemClickListener chboxListener, Utils.ItemClickListener deleteBtnListener, Utils.ItemClickListener undeleteBtnListener) { this.mList = list; this.chboxListener = chboxListener; this.deleteBtnListener = deleteBtnListener; @@ -49,24 +48,16 @@ public class ModulesAdapter extends RecyclerView.Adapter chboxListener.onItemClick(compoundButton, holder.getAdapterPosition())); - holder.delete.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (module.willBeRemoved()) { - unDeleteBtnListener.onItemClick(holder.delete, holder.getAdapterPosition()); - } else { - deleteBtnListener.onItemClick(holder.delete, holder.getAdapterPosition()); - } - - updateDeleteButton(holder, module); + holder.delete.setOnClickListener(view -> { + if (module.willBeRemoved()) { + unDeleteBtnListener.onItemClick(holder.delete, holder.getAdapterPosition()); + } else { + deleteBtnListener.onItemClick(holder.delete, holder.getAdapterPosition()); } + + updateDeleteButton(holder, module); }); updateDeleteButton(holder, module); diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index c28d0428d..6f795d77b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -28,13 +28,8 @@ import butterknife.ButterKnife; public class ModulesFragment extends Fragment { - private static final String MAGISK_PATH = "/magisk"; - private static final String MAGISK_CACHE_PATH = "/cache/magisk"; - - private static List listModules = new ArrayList<>(); - private static List listModulesCache = new ArrayList<>(); - - public static loadModules loadMod; + public static List listModules = new ArrayList<>(); + public static List listModulesCache = new ArrayList<>(); @BindView(R.id.progressBar) ProgressBar progressBar; @BindView(R.id.pager) ViewPager viewPager; @@ -67,8 +62,7 @@ public class ModulesFragment extends Fragment { progressBar.setVisibility(View.VISIBLE); viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); - loadMod = new loadModules(); - loadMod.execute(); + new Utils.LoadModules(getContext()).execute(); new updateUI().execute(); break; } @@ -94,40 +88,10 @@ public class ModulesFragment extends Fragment { } - public static class loadModules extends AsyncTask { - - @Override - protected Void doInBackground(Void... voids) { - listModules.clear(); - listModulesCache.clear(); - List magisk = Utils.getModList(MAGISK_PATH); - List magiskCache = Utils.getModList(MAGISK_CACHE_PATH); - if (!magisk.isEmpty()) { - for (String mod : magisk) { - listModules.add(new Module(mod)); - } - } - if (!magiskCache.isEmpty()) { - for (String mod : magiskCache) { - listModulesCache.add(new Module(mod)); - } - } - - return null; - } - } - private class updateUI extends AsyncTask { @Override protected Void doInBackground(Void... voids) { - // Ensure loadMod is done - try { - loadMod.get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } - return null; } diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java index ed5ae920a..a7b1a9377 100644 --- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java @@ -3,14 +3,12 @@ package com.topjohnwu.magisk; import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.annotation.IdRes; import android.support.annotation.NonNull; import android.support.design.widget.NavigationView; -import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; @@ -22,7 +20,7 @@ import android.support.v7.widget.Toolbar; import android.view.MenuItem; import android.view.View; -import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.Utils; import butterknife.BindView; import butterknife.ButterKnife; @@ -50,10 +48,14 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } - // Load mods in the background, as it is time consuming - ModulesFragment.loadMod = new ModulesFragment.loadModules(); - ModulesFragment.loadMod.execute(); - new Popups().execute(); + // Startups + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); + } + new Utils.Initialize(this).execute(); + new Utils.CheckUpdates(this).execute(); + new Utils.LoadModules(this).execute(); setSupportActionBar(toolbar); @@ -84,10 +86,6 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView navigationView.setNavigationItemSelectedListener(this); - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); - } } @Override @@ -156,20 +154,4 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView } } } - - private class Popups extends AsyncTask { - - @Override - protected Boolean doInBackground(Void... voids) { - return Shell.rootAccess(); - } - - @Override - protected void onPostExecute(Boolean rootAccess) { - super.onPostExecute(rootAccess); - if (!rootAccess) { - Snackbar.make(findViewById(android.R.id.content), R.string.no_root_access, Snackbar.LENGTH_LONG).show(); - } - } - } } diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Module.java b/app/src/main/java/com/topjohnwu/magisk/module/Module.java index 2c0109373..74afbe3ab 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -2,6 +2,7 @@ package com.topjohnwu.magisk.module; import android.util.Log; +import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.utils.Utils; import java.io.BufferedReader; @@ -13,13 +14,16 @@ public class Module { private String mRemoveFile; private String mDisableFile; - private String mName; - private String mVersion; - private String mDescription; + private String mName = null; + private String mVersion = "(No version provided)"; + private String mDescription = "(No description provided)"; private boolean mEnable; private boolean mRemove; + private String mId; + private int mVersionCode; + public Module(String path) { mRemoveFile = path + "/remove"; @@ -46,9 +50,25 @@ public class Module { case "description": mDescription = value; break; + case "id": + mId = value; + break; + case "versionCode": + try { + mVersionCode = Integer.parseInt(value); + } catch (NumberFormatException e) { + mVersionCode = 0; + } + break; } } + if (mName == null) { + int sep = path.lastIndexOf('/'); + mName = path.substring(sep + 1); + mId = mName; + } + mEnable = !Utils.fileExist(mDisableFile); mRemove = Utils.fileExist(mRemoveFile); diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/ApkReceiver.java b/app/src/main/java/com/topjohnwu/magisk/receivers/ApkReceiver.java deleted file mode 100644 index 8a81bbac3..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/receivers/ApkReceiver.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.topjohnwu.magisk.receivers; - -import android.content.Intent; -import android.support.v4.content.FileProvider; - -import java.io.File; - -public class ApkReceiver extends DownloadReceiver { - - @Override - public void task(File file) { - Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE); - install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - install.setData(FileProvider.getUriForFile(mContext, "com.topjohnwu.magisk.provider", file)); - mContext.startActivity(install); - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java b/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java deleted file mode 100644 index 8227a4d25..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.topjohnwu.magisk.receivers; - -import android.app.DownloadManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.support.v4.content.FileProvider; -import android.widget.Toast; - -import com.topjohnwu.magisk.R; - -import java.io.File; - -/** - * Created by topjohnwu - */ -public abstract class DownloadReceiver extends BroadcastReceiver { - public Context mContext; - long downloadID; - - @Override - public void onReceive(Context context, Intent intent) { - mContext = context; - DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - String action = intent.getAction(); - if(DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)){ - DownloadManager.Query query = new DownloadManager.Query(); - query.setFilterById(downloadID); - Cursor c = downloadManager.query(query); - if (c.moveToFirst()) { - int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS); - int status = c.getInt(columnIndex); - switch (status) { - case DownloadManager.STATUS_SUCCESSFUL: - File file = new File(Uri.parse(c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))).getPath()); - task(file); - break; - default: - Toast.makeText(context, R.string.error_download_file, Toast.LENGTH_LONG).show(); - break; - } - context.unregisterReceiver(this); - } - } - } - - public void setDownloadID(long id) { downloadID = id;} - - public abstract void task(File file); -} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/ZipReceiver.java b/app/src/main/java/com/topjohnwu/magisk/receivers/ZipReceiver.java deleted file mode 100644 index bd29aaae3..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/receivers/ZipReceiver.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.topjohnwu.magisk.receivers; - -import android.support.v7.app.AlertDialog; - -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Utils; - -import java.io.File; - -public class ZipReceiver extends DownloadReceiver { - @Override - public void task(File file) { - new AlertDialog.Builder(mContext) - .setTitle("Installation") - .setMessage("Do you want to install now?") - .setCancelable(false) - .setPositiveButton("Yes, flash now", (dialogInterface, i) -> { - new Utils.flashZIP(file.getPath(), mContext).execute(); - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/rv/ItemClickListener.java b/app/src/main/java/com/topjohnwu/magisk/rv/ItemClickListener.java deleted file mode 100644 index eeb0e80d1..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/rv/ItemClickListener.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.topjohnwu.magisk.rv; - -import android.view.View; - -public interface ItemClickListener { - - void onItemClick(View view, int position); - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java b/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java index c91c46e46..718adb64f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java @@ -17,7 +17,6 @@ public class Shell { // -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted; 2 = improperly rooted; public static int rootStatus; - public static int magiskVersion; private static Process rootShell; private static DataOutputStream rootSTDIN; @@ -30,13 +29,6 @@ public class Shell { private static void init() { - List ret = sh("getprop magisk.version"); - if (ret.get(0).replaceAll("\\s", "").isEmpty()) { - magiskVersion = -1; - } else { - magiskVersion = Integer.parseInt(ret.get(0)); - } - try { rootShell = Runtime.getRuntime().exec(sh("getprop magisk.supath").get(0) + "/su"); rootStatus = 1; @@ -56,7 +48,7 @@ public class Shell { rootSTDOUT = new StreamGobbler(rootShell.getInputStream(), rootOutList); rootSTDOUT.start(); - ret = su("echo -BOC-", "id"); + List ret = su("echo -BOC-", "id"); if (ret == null) { // Something wrong with root, not allowed? rootStatus = -1; diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java index d8607e29f..c36710f21 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -1,17 +1,48 @@ package com.topjohnwu.magisk.utils; +import android.Manifest; +import android.app.Activity; +import android.app.DownloadManager; import android.app.ProgressDialog; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; import android.os.AsyncTask; +import android.os.Environment; +import android.support.design.widget.Snackbar; +import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; +import android.view.View; import android.widget.Toast; +import com.topjohnwu.magisk.ModulesFragment; import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.module.Module; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.List; public class Utils { + public static int magiskVersion, remoteMagiskVersion = -1, remoteAppVersion = -1; + public static String magiskLink, magiskChangelog, appChangelog, appLink, phhLink, supersuLink; + + public static final String MAGISK_PATH = "/magisk"; + public static final String MAGISK_CACHE_PATH = "/cache/magisk"; + public static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json"; + public static boolean fileExist(String path) { List ret; ret = Shell.sh("if [ -f " + path + " ]; then echo true; else echo false; fi"); @@ -37,33 +68,336 @@ public class Utils { public static List getModList(String path) { List ret; - ret = Shell.sh("find " + path + " -type d -maxdepth 1 | while read ITEM ; do if [ -f $ITEM/module.prop ]; then echo $ITEM; fi; done"); - if (ret.isEmpty() && Shell.rootAccess()) ret = Shell.su("find " + path + " -type d -maxdepth 1 | while read ITEM ; do if [ -f $ITEM/module.prop ]; then echo $ITEM; fi; done"); + ret = Shell.sh("find " + path + " -type d -maxdepth 1 ! -name \"*.core\" ! -name \"*lost+found\" ! -name \"*magisk\""); + if (ret.isEmpty() && Shell.rootAccess()) + ret = Shell.su("find " + path + " -type d -maxdepth 1 ! -name \"*.core\" ! -name \"*lost+found\" ! -name \"*magisk\""); return ret; } public static List readFile(String path) { List ret; ret = Shell.sh("cat " + path); - if (ret.isEmpty() && Shell.rootAccess()) ret = Shell.su("cat " + path); + if (ret.isEmpty() && Shell.rootAccess()) + ret = Shell.su("cat " + path); return ret; } - public static class flashZIP extends AsyncTask { + public static void downloadAndReceive(Context context, DownloadReceiver receiver, String link, String file) { + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + Toast.makeText(context, R.string.permissionNotGranted, Toast.LENGTH_LONG).show(); + return; + } + File downloadFile, dir = new File(Environment.getExternalStorageDirectory() + "/MagiskManager"); + downloadFile = new File(dir + "/" + file); + if (!dir.exists()) dir.mkdir(); + if (downloadFile.exists()) downloadFile.delete(); - private String mPath; - private ProgressDialog progress; - Context mContext; + DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager.Request request = new DownloadManager.Request(Uri.parse(link)); + request.setDestinationUri(Uri.fromFile(downloadFile)); - public flashZIP(String path, Context context) { - mPath = path; + receiver.setDownloadID(downloadManager.enqueue(request)); + context.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); + } + + public abstract static class DownloadReceiver extends BroadcastReceiver { + public Context mContext; + long downloadID; + public String mName; + + public DownloadReceiver() {} + public DownloadReceiver(String name) { mName = name; } + + @Override + public void onReceive(Context context, Intent intent) { mContext = context; + DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + String action = intent.getAction(); + if(DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)){ + DownloadManager.Query query = new DownloadManager.Query(); + query.setFilterById(downloadID); + Cursor c = downloadManager.query(query); + if (c.moveToFirst()) { + int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS); + int status = c.getInt(columnIndex); + switch (status) { + case DownloadManager.STATUS_SUCCESSFUL: + File file = new File(Uri.parse(c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))).getPath()); + task(file); + break; + default: + Toast.makeText(context, R.string.download_file_error, Toast.LENGTH_LONG).show(); + break; + } + context.unregisterReceiver(this); + } + } + } + + public void setDownloadID(long id) { downloadID = id;} + public abstract void task(File file); + } + + public static class Initialize extends AsyncTask { + + private Context mContext; + + public Initialize(Context context) { + mContext = context; + } + + @Override + protected Void doInBackground(Void... voids) { + List ret = Shell.sh("getprop magisk.version"); + if (ret.get(0).replaceAll("\\s", "").isEmpty()) { + magiskVersion = -1; + } else { + magiskVersion = Integer.parseInt(ret.get(0)); + } + + // Install Busybox and set as top priority + if (Shell.rootAccess()) { + String busybox = mContext.getApplicationInfo().nativeLibraryDir + "/libbusybox.so"; + Shell.su( + "rm -rf /data/busybox", + "mkdir -p /data/busybox", + "cp -af " + busybox + " /data/busybox/busybox", + "chmod 755 /data/busybox /data/busybox/busybox", + "chcon u:object_r:system_file:s0 /data/busybox /data/busybox/busybox", + "/data/busybox/busybox --install -s /data/busybox", + "rm -f /data/busybox/su", + "export PATH=/data/busybox:$PATH" + ); + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + if (!Shell.rootAccess()) { + Snackbar.make(((Activity)mContext).findViewById(android.R.id.content), R.string.no_root_access, Snackbar.LENGTH_LONG).show(); + } + + } + } + + public static class CheckUpdates extends AsyncTask { + + private Context mContext; + + public CheckUpdates(Context context) { + mContext = context; + } + + @Override + protected Void doInBackground(Void... voids) { + try { + HttpURLConnection c = (HttpURLConnection) new URL(UPDATE_JSON).openConnection(); + c.setRequestMethod("GET"); + c.setInstanceFollowRedirects(false); + c.setDoOutput(false); + c.connect(); + + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + } + br.close(); + JSONObject json = new JSONObject(sb.toString()); + JSONObject magisk = json.getJSONObject("magisk"); + JSONObject app = json.getJSONObject("app"); + JSONObject root = json.getJSONObject("root"); + + remoteMagiskVersion = magisk.getInt("versionCode"); + magiskLink = magisk.getString("link"); + magiskChangelog = magisk.getString("changelog"); + + remoteAppVersion = app.getInt("versionCode"); + appLink = app.getString("link"); + appChangelog = app.getString("changelog"); + + phhLink = root.getString("phh"); + supersuLink = root.getString("supersu"); + + } catch (IOException | JSONException ignored) { + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + if (Shell.rootAccess() && magiskVersion == -1) { + new AlertDialog.Builder(mContext) + .setTitle(R.string.no_magisk_title) + .setMessage(R.string.no_magisk_msg) + .setCancelable(true) + .setPositiveButton(R.string.download_install, (dialogInterface, i) -> { + new AlertDialog.Builder(mContext) + .setTitle(R.string.root_method_title) + .setItems(new String[]{mContext.getString(R.string.phh), mContext.getString(R.string.supersu)}, (dialogInterface1, root) -> { + DownloadReceiver rootReceiver; + String link, filename; + switch (root) { + case 0: + link = phhLink; + filename = "phhsu.zip"; + rootReceiver = new DownloadReceiver(mContext.getString(R.string.phh)) { + @Override + public void task(File file) { + new RemoveSystemSU().execute(); + new FlashZIP(mContext, mName, file.getPath()).execute(); + } + }; + break; + case 1: + link = supersuLink; + filename = "supersu.zip"; + rootReceiver = new DownloadReceiver(mContext.getString(R.string.supersu)) { + @Override + public void task(File file) { + new RemoveSystemSU().execute(); + new FlashZIP(mContext, mName, file.getPath()).execute(); + } + }; + break; + default: + rootReceiver = null; + link = filename = null; + } + DownloadReceiver magiskReceiver = new DownloadReceiver(mContext.getString(R.string.magisk)) { + @Override + public void task(File file) { + Context temp = mContext; + new FlashZIP(mContext, mName, file.getPath()) { + @Override + protected void done() { + downloadAndReceive(temp, rootReceiver, link, filename); + } + }.execute(); + } + }; + downloadAndReceive(mContext, magiskReceiver, magiskLink, "latest_magisk.zip"); + }) + .show(); + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } else if (Shell.rootStatus == 2) { + new AlertDialog.Builder(mContext) + .setTitle(R.string.root_system) + .setMessage(R.string.root_system_msg) + .setCancelable(true) + .setPositiveButton(R.string.download_install, (dialogInterface, i) -> { + new AlertDialog.Builder(mContext) + .setTitle(R.string.root_method_title) + .setItems(new String[]{mContext.getString(R.string.phh), mContext.getString(R.string.supersu)}, (dialogInterface1, root) -> { + switch(root) + { + case 0: + downloadAndReceive( + mContext, + new DownloadReceiver(mContext.getString(R.string.phh)) { + @Override + public void task(File file) { + new FlashZIP(mContext, mName, file.getPath()).execute(); + } + }, + phhLink, "phhsu.zip"); + break; + case 1: + downloadAndReceive( + mContext, + new DownloadReceiver(mContext.getString(R.string.supersu)) { + @Override + public void task(File file) { + new FlashZIP(mContext, mName, file.getPath()).execute(); + } + }, + supersuLink, "supersu.zip"); + break; + } + }) + .show(); + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } + } + } + + public static class RemoveSystemSU extends AsyncTask { + + @Override + protected Void doInBackground(Void... voids) { + Shell.su( + "umount /system/xbin", + "umount -l /system/xbin", + "if [ ! -z $(which su | grep system) ]; then", + "mount -o rw,remount /system", + "rm -rf /system/.pin /system/app/SuperSU /system/bin/.ext /system/etc/.installed_su_daemon " + + "/system/etc/install-recovery.sh /system/etc/init.d/99SuperSUDaemon /system/xbin/daemonsu " + + "/system/xbin/su /system/xbin/sugote /system/xbin/sugote-mksh /system/xbin/supolicy " + + "/data/app/eu.chainfire.supersu-*", + "mv -f /system/bin/app_process32_original /system/bin/app_process32", + "mv -f /system/bin/app_process64_original /system/bin/app_process64", + "mv -f /system/bin/install-recovery_original.sh /system/bin/install-recovery.sh", + "if [ -e /system/bin/app_process64 ]; then", + "ln -sf /system/bin/app_process64 /system/bin/app_process", + "else", + "ln -sf /system/bin/app_process32 /system/bin/app_process", + "fi", + "umount /system", + "fi", + "setprop magisk.root 1" + ); + return null; + } + } + + public static class LoadModules extends AsyncTask { + + private Context mContext; + + public LoadModules(Context context) { + mContext = context; + } + + @Override + protected Void doInBackground(Void... voids) { + ModulesFragment.listModules.clear(); + ModulesFragment.listModulesCache.clear(); + List magisk = getModList(MAGISK_PATH); + List magiskCache = getModList(MAGISK_CACHE_PATH); + for (String mod : magisk) { + ModulesFragment.listModules.add(new Module(mod)); + } + for (String mod : magiskCache) { + ModulesFragment.listModulesCache.add(new Module(mod)); + } + return null; + } + } + + public static class FlashZIP extends AsyncTask { + + private String mPath, mName; + private ProgressDialog progress; + private Context mContext; + + public FlashZIP(Context context, String name, String path) { + mContext = context; + mName = name; + mPath = path; } @Override protected void onPreExecute() { super.onPreExecute(); - progress = ProgressDialog.show(mContext, "Installing", "Patching boot image for Magisk...."); + progress = ProgressDialog.show(mContext, mContext.getString(R.string.zip_install_progress_title), mContext.getString(R.string.zip_install_progress_msg, mName)); } @Override @@ -71,14 +405,15 @@ public class Utils { if (!Shell.rootAccess()) { return false; } else { - Shell.su( + List ret = Shell.su( "rm -rf /data/tmp", "mkdir -p /data/tmp", "cp -af " + mPath + " /data/tmp/install.zip", "unzip -o /data/tmp/install.zip META-INF/com/google/android/* -d /data/tmp", - "BOOTMODE=true sh /data/tmp/META-INF/com/google/android/update-binary dummy 1 /data/tmp/install.zip" + "BOOTMODE=true sh /data/tmp/META-INF/com/google/android/update-binary dummy 1 /data/tmp/install.zip", + "if [ $? -eq 0 ]; then echo true; else echo false; fi" ); - return Boolean.parseBoolean(Shell.su("if [ $? -eq 0 ]; then echo true; else echo false; fi").get(0)); + return Boolean.parseBoolean(ret.get(ret.size() -1)); } } @@ -88,15 +423,25 @@ public class Utils { Shell.su("rm -rf /data/tmp"); progress.dismiss(); if (!result) { - Toast.makeText(mContext, "Installation failed...", Toast.LENGTH_LONG).show(); + Toast.makeText(mContext, mContext.getString(R.string.manual_install, mPath), Toast.LENGTH_LONG).show(); return; } + done(); + } + + protected void done() { new AlertDialog.Builder(mContext) - .setTitle("Reboot now?") - .setPositiveButton("Yes", (dialogInterface1, i1) -> Toast.makeText(mContext, "Reboot...", Toast.LENGTH_LONG).show()) + .setTitle(R.string.reboot_title) + .setMessage(R.string.reboot_msg) + .setPositiveButton(R.string.reboot, (dialogInterface1, i) -> Shell.su("reboot")) .setNegativeButton(R.string.no_thanks, null) .show(); } } + public interface ItemClickListener { + + void onItemClick(View view, int position); + + } } diff --git a/app/src/main/jniLibs/armeabi/libbusybox.so b/app/src/main/jniLibs/armeabi/libbusybox.so new file mode 100644 index 000000000..67bfb88e1 Binary files /dev/null and b/app/src/main/jniLibs/armeabi/libbusybox.so differ diff --git a/app/src/main/jniLibs/x86/libbusybox.so b/app/src/main/jniLibs/x86/libbusybox.so new file mode 100644 index 000000000..a7462efe8 Binary files /dev/null and b/app/src/main/jniLibs/x86/libbusybox.so differ diff --git a/app/src/main/res/menu/menu_module.xml b/app/src/main/res/menu/menu_module.xml index 89c86877c..fffc6982c 100644 --- a/app/src/main/res/menu/menu_module.xml +++ b/app/src/main/res/menu/menu_module.xml @@ -5,7 +5,7 @@ \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 1a5252c7c..52427843f 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,6 +1,5 @@ - Magisk Manager Info su… Changelog dell\'app Sviluppatori principali @@ -11,8 +10,6 @@ Moduli in cache Il modulo verrà disabilitato al prossimo riavvio Il modulo verrà abilitato al prossimo riavvio - Aggiorna - Caricamento… Log Il log è vuoto Non è possibile leggere il log: diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b7027aa74..983a104e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,10 +1,28 @@ - Magisk Manager - + + Magisk Manager Magisk + + + Open navigation drawer + Close navigation drawer + Root + Modules + Log + + Installed Magisk v%1$s Have you installed Magisk? + Magisk Manager App v%1$s update! + Magisk v%1$s update! + Cannot check for updates + Latest version of %1$s installed + + + Root Toggle + SELinux Toggle + Root Error Safety Net Status Unknown Not Rooted @@ -13,7 +31,7 @@ Root mounted and enabled. Safety Net (Android Pay) will NOT work Root not mounted Safety Net (Android Pay) should work, but no root temporarily\nYou might need to manually add a card in Android Pay app to refresh the root status of AP - Improperly Installed + Magisk Incompatible Root Detected Root improperly installed. Safety Net (Android Pay) will NOT work, and impossible to toggle SELinux Status Unknown @@ -21,17 +39,15 @@ SELinux is permissive\nOnly turn off SELinux if necessary! Samsung need custom kernel for switching SELinux status! - Root Toggle - SELinux Toggle - - Open navigation drawer - Close navigation drawer - - Modules - Log - No root access, functionality limited + + Cache modules + No modules found Module will be removed at next reboot + Module will not be removed at next reboot Module will be disabled at next reboot + Module will be enabled at next reboot + + Save to SD Send Reload @@ -41,10 +57,8 @@ Could not clear the log: Log is empty Could not write log to SD card: - This feature will not work without permission to write external storage. - Module will be enabled at next reboot - Module will not be removed at next reboot - Cache modules + + About Main developers topjohnwu in collaboration with dvdandroid]]> @@ -54,20 +68,25 @@ Source code App\'s translators Support thread - Refresh - No modules found - Loading… - Update available! - Download - Version: v%2$s
Changelog:
%3$s]]>
- No, thanks - Don\'t show again - Error downloading file - File downloaded in Magisk directory, you can flash it in recovery - Root - Magisk Manager App v%1$s update! - Magisk v%1$s update! - Cannot check for updates - Latest version of %1$s installed + + This feature will not work without permission to write external storage. + No root access, functionality limited + No thanks + %1$s Update! + Changelog:
%3$s]]>
+ Download and install + Error downloading file + File downloaded in %1$s\nFlash it in recovery manually + Installation succeeded! + Do you want to reboot now? + Reboot + Installing + "Installing %1$s …" + No Magisk Installed! + Do you want to download and install Magisk? + Choose a root method + phh\'s superuser + SuperSU + It seems that you have incompatible root installed\nDo you want to install Magisk compatible root now?