diff --git a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java index 903ab1ef2..44eea0df0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java @@ -226,7 +226,7 @@ public class LogFragment extends Fragment { return llog.toString(); } else { - if (Utils.removeFile(MAGISK_LOG)) { + if (Utils.removeItem(MAGISK_LOG)) { Snackbar.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show(); } else { Snackbar.make(txtLog, R.string.logs_clear_failed, Snackbar.LENGTH_SHORT).show(); diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java index ab41494d6..87c55ec32 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -35,13 +35,15 @@ import butterknife.ButterKnife; public class ReposAdapter extends RecyclerView.Adapter { - private final List mList; + private List mUpdateRepos, mInstalledRepos, mOthersRepos; private View mView; private Context context; private AlertDialog.Builder builder; - public ReposAdapter(List list) { - mList = list; + public ReposAdapter(List update, List installed, List others) { + mUpdateRepos = update; + mInstalledRepos = installed; + mOthersRepos = others; } @Override @@ -62,7 +64,18 @@ public class ReposAdapter extends RecyclerView.Adapter @Override public void onBindViewHolder(final ViewHolder holder, int position) { - final Repo repo = mList.get(position); + final Repo repo; + if (position >= mUpdateRepos.size()) { + position -= mUpdateRepos.size(); + if (position >= mInstalledRepos.size()) { + position -= mInstalledRepos.size(); + repo = mOthersRepos.get(position); + } else { + repo = mInstalledRepos.get(position); + } + } else { + repo = mUpdateRepos.get(position); + } if (repo.isCache()) { holder.title.setText("[Cache] " + repo.getName()); } else { @@ -140,7 +153,7 @@ public class ReposAdapter extends RecyclerView.Adapter @Override public int getItemCount() { - return mList.size(); + return mUpdateRepos.size() + mInstalledRepos.size() + mOthersRepos.size(); } class ViewHolder extends RecyclerView.ViewHolder { diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java index 3b66a86e2..3b7211d6f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -6,11 +6,15 @@ import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.Nullable; +import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.SearchView; import android.widget.TextView; import com.topjohnwu.magisk.module.Repo; @@ -29,20 +33,34 @@ public class ReposFragment extends Fragment { @BindView(R.id.recyclerView) RecyclerView recyclerView; @BindView(R.id.empty_rv) TextView emptyTv; @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; - private List mListRepos = new ArrayList<>(); + private List mUpdateRepos = new ArrayList<>(); private List mInstalledRepos = new ArrayList<>(); private List mOthersRepos = new ArrayList<>(); + private List fUpdateRepos = new ArrayList<>(); + private List fInstalledRepos = new ArrayList<>(); + private List fOthersRepos = new ArrayList<>(); + + private ReposAdapter mReposAdapter = new ReposAdapter(fUpdateRepos, fInstalledRepos, fOthersRepos); + private SimpleSectionedRecyclerViewAdapter mSectionedAdapter; + private SharedPreferences.OnSharedPreferenceChangeListener listener; private SharedPreferences prefs; + private SearchView.OnQueryTextListener searchListener; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.repos_fragment, container, false); + ButterKnife.bind(this, view); + mSectionedAdapter = new + SimpleSectionedRecyclerViewAdapter(getActivity(), R.layout.section, R.id.section_text, mReposAdapter); + + recyclerView.setAdapter(mSectionedAdapter); + mSwipeRefreshLayout.setRefreshing(true); prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); @@ -54,6 +72,7 @@ public class ReposFragment extends Fragment { }); if (prefs.getBoolean("repo_done", false)) { + reloadRepos(); updateUI(); } @@ -61,22 +80,66 @@ public class ReposFragment extends Fragment { if (s.equals("repo_done")) { if (pref.getBoolean(s, false)) { Logger.dev("ReposFragment: UI refresh triggered"); + reloadRepos(); updateUI(); } } }; + searchListener = new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + fUpdateRepos.clear(); + fInstalledRepos.clear(); + fOthersRepos.clear(); + for (Repo repo: mUpdateRepos) { + if (repo.getName().toLowerCase().contains(newText.toLowerCase()) + || repo.getAuthor().toLowerCase().contains(newText.toLowerCase()) + || repo.getDescription().toLowerCase().contains(newText.toLowerCase()) + ) { + fUpdateRepos.add(repo); + } + } + for (Repo repo: mInstalledRepos) { + if (repo.getName().toLowerCase().contains(newText.toLowerCase()) + || repo.getAuthor().toLowerCase().contains(newText.toLowerCase()) + || repo.getDescription().toLowerCase().contains(newText.toLowerCase()) + ) { + fInstalledRepos.add(repo); + } + } + for (Repo repo: mOthersRepos) { + if (repo.getName().toLowerCase().contains(newText.toLowerCase()) + || repo.getAuthor().toLowerCase().contains(newText.toLowerCase()) + || repo.getDescription().toLowerCase().contains(newText.toLowerCase()) + ) { + fOthersRepos.add(repo); + } + } + updateUI(); + return false; + } + }; + return view; } @Override - public void onAttachFragment(Fragment childFragment) { - super.onAttachFragment(childFragment); + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.menu_repo, menu); + SearchView search = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.repo_search)); + search.setOnQueryTextListener(searchListener); } @Override public void onResume() { super.onResume(); + setHasOptionsMenu(true); prefs.registerOnSharedPreferenceChangeListener(listener); } @@ -86,32 +149,34 @@ public class ReposFragment extends Fragment { prefs.unregisterOnSharedPreferenceChangeListener(listener); } - private void updateUI() { + private void reloadRepos() { ModuleHelper.getRepoLists(mUpdateRepos, mInstalledRepos, mOthersRepos); - mListRepos.clear(); - mListRepos.addAll(mUpdateRepos); - mListRepos.addAll(mInstalledRepos); - mListRepos.addAll(mOthersRepos); - if (mListRepos.size() == 0) { + fUpdateRepos.clear(); + fInstalledRepos.clear(); + fOthersRepos.clear(); + fUpdateRepos.addAll(mUpdateRepos); + fInstalledRepos.addAll(mInstalledRepos); + fOthersRepos.addAll(mOthersRepos); + } + + private void updateUI() { + if (fUpdateRepos.size() + fInstalledRepos.size() + fOthersRepos.size() == 0) { emptyTv.setVisibility(View.VISIBLE); recyclerView.setVisibility(View.GONE); } else { List sections = new ArrayList<>(); - if (!mUpdateRepos.isEmpty()) { + if (!fUpdateRepos.isEmpty()) { sections.add(new SimpleSectionedRecyclerViewAdapter.Section(0, getString(R.string.update_available))); } - if (!mInstalledRepos.isEmpty()) { - sections.add(new SimpleSectionedRecyclerViewAdapter.Section(mUpdateRepos.size(), getString(R.string.installed))); + if (!fInstalledRepos.isEmpty()) { + sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size(), getString(R.string.installed))); } - if (!mOthersRepos.isEmpty()) { - sections.add(new SimpleSectionedRecyclerViewAdapter.Section(mUpdateRepos.size() + mInstalledRepos.size(), getString(R.string.not_installed))); + if (!fOthersRepos.isEmpty()) { + sections.add(new SimpleSectionedRecyclerViewAdapter.Section(fUpdateRepos.size() + fInstalledRepos.size(), getString(R.string.not_installed))); } SimpleSectionedRecyclerViewAdapter.Section[] array = sections.toArray(new SimpleSectionedRecyclerViewAdapter.Section[sections.size()]); - SimpleSectionedRecyclerViewAdapter mSectionedAdapter = new - SimpleSectionedRecyclerViewAdapter(getActivity(), R.layout.section, R.id.section_text, new ReposAdapter(mListRepos)); mSectionedAdapter.setSections(array); recyclerView.setVisibility(View.VISIBLE); - recyclerView.setAdapter(mSectionedAdapter); } mSwipeRefreshLayout.setRefreshing(false); } diff --git a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java index bb942e833..cf1df057c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java @@ -75,11 +75,13 @@ public class SettingsActivity extends AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.uisettings); - PreferenceManager.setDefaultValues(getActivity(), R.xml.uisettings, false); + addPreferencesFromResource(R.xml.app_settings); + PreferenceManager.setDefaultValues(getActivity(), R.xml.app_settings, false); themePreference = (ListPreference) findPreference("theme"); CheckBoxPreference busyboxPreference = (CheckBoxPreference) findPreference("busybox"); + CheckBoxPreference magiskhidePreference = (CheckBoxPreference) findPreference("magiskhide"); + magiskhidePreference.setChecked(Utils.itemExist(false, "/magisk/.core/magiskhide/enable")); busyboxPreference.setChecked(Utils.commandExists("unzip")); PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(this); @@ -88,8 +90,10 @@ public class SettingsActivity extends AppCompatActivity { if (MagiskFragment.magiskVersion == -1) { busyboxPreference.setEnabled(false); + magiskhidePreference.setEnabled(false); } else { busyboxPreference.setEnabled(true); + magiskhidePreference.setEnabled(true); } } @@ -124,8 +128,28 @@ public class SettingsActivity extends AppCompatActivity { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); break; + case "magiskhide": + boolean checked = sharedPreferences.getBoolean("magiskhide", false); + if (checked) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... params) { + Utils.createFile("/magisk/.core/magiskhide/enable"); + return null; + } + }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); + } else { + new AsyncTask() { + @Override + protected Void doInBackground(Void... params) { + Utils.removeItem("/magisk/.core/magiskhide/enable"); + return null; + } + }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); + } + break; case "busybox": - boolean checked = sharedPreferences.getBoolean("busybox", false); + checked = sharedPreferences.getBoolean("busybox", false); new Async.LinkBusyBox(checked).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); break; case "developer_logging": 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 c87ff59ec..465aeaeaf 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -60,7 +60,7 @@ public class Module extends BaseModule { new AsyncTask() { @Override protected Void doInBackground(Void... voids) { - mEnable = Utils.removeFile(mDisableFile); + mEnable = Utils.removeItem(mDisableFile); return null; } }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); @@ -84,7 +84,7 @@ public class Module extends BaseModule { new AsyncTask() { @Override protected Void doInBackground(Void... voids) { - mRemove = !Utils.removeFile(mRemoveFile); + mRemove = !Utils.removeItem(mRemoveFile); return null; } }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Async.java b/app/src/main/java/com/topjohnwu/magisk/utils/Async.java index 58003e11d..4398f3f2e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Async.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Async.java @@ -200,7 +200,7 @@ public class Async { InputStream in = mContext.getContentResolver().openInputStream(mUri); mFile = new File(mContext.getCacheDir().getAbsolutePath() + "/install.zip"); mFile.delete(); - Utils.removeFile(mFile.getPath()); + Utils.removeItem(mFile.getPath()); createFileFromInputStream(in, mFile); in.close(); } catch (FileNotFoundException e) { @@ -273,7 +273,7 @@ public class Async { } } if (mFile != null && mFile.exists() && !mFile.delete()) { - Utils.removeFile(mFile.getPath()); + Utils.removeItem(mFile.getPath()); } if (ret != null && Boolean.parseBoolean(ret.get(ret.size() - 1))) { return 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 f374a9865..3d389c8d3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -7,13 +7,11 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Environment; -import android.preference.PreferenceManager; import android.support.v4.app.ActivityCompat; import android.util.Base64; import android.view.View; import android.widget.Toast; -import com.topjohnwu.magisk.MagiskFragment; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.receivers.DownloadReceiver; @@ -68,8 +66,8 @@ public class Utils { return Shell.rootAccess() && Boolean.parseBoolean(Shell.su(command).get(0)); } - public static boolean removeFile(String path) { - String command = "rm -f " + path + " 2>/dev/null; if [ -f " + path + " ]; then echo false; else echo true; fi"; + public static boolean removeItem(String path) { + String command = "rm -rf " + path + " 2>/dev/null; if [ -e " + path + " ]; then echo false; else echo true; fi"; return Shell.rootAccess() && Boolean.parseBoolean(Shell.su(command).get(0)); } diff --git a/app/src/main/res/menu/menu_log.xml b/app/src/main/res/menu/menu_log.xml index 1b5c0ea5b..df78a72c3 100644 --- a/app/src/main/res/menu/menu_log.xml +++ b/app/src/main/res/menu/menu_log.xml @@ -1,6 +1,6 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 96e25c96f..68474d228 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -98,6 +98,8 @@ Check this to enable more verbose logging. Enable shell command debug logging Check this to enable logging all shell commands and output + Enable Magisk Hide + Reboot to apply settings diff --git a/app/src/main/res/xml/uisettings.xml b/app/src/main/res/xml/app_settings.xml similarity index 81% rename from app/src/main/res/xml/uisettings.xml rename to app/src/main/res/xml/app_settings.xml index c256b37b6..b56b59563 100644 --- a/app/src/main/res/xml/uisettings.xml +++ b/app/src/main/res/xml/app_settings.xml @@ -12,6 +12,17 @@ android:entries="@array/themes" android:entryValues="@array/themes"/> + + + + + +