Add search bar & Magisk Hide option

This commit is contained in:
topjohnwu 2016-10-17 10:11:26 +08:00
parent a7da6cf172
commit 70500cf21e
12 changed files with 158 additions and 36 deletions

View File

@ -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();

View File

@ -35,13 +35,15 @@ import butterknife.ButterKnife;
public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder> {
private final List<Repo> mList;
private List<Repo> mUpdateRepos, mInstalledRepos, mOthersRepos;
private View mView;
private Context context;
private AlertDialog.Builder builder;
public ReposAdapter(List<Repo> list) {
mList = list;
public ReposAdapter(List<Repo> update, List<Repo> installed, List<Repo> others) {
mUpdateRepos = update;
mInstalledRepos = installed;
mOthersRepos = others;
}
@Override
@ -62,7 +64,18 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
@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<ReposAdapter.ViewHolder>
@Override
public int getItemCount() {
return mList.size();
return mUpdateRepos.size() + mInstalledRepos.size() + mOthersRepos.size();
}
class ViewHolder extends RecyclerView.ViewHolder {

View File

@ -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<Repo> mListRepos = new ArrayList<>();
private List<Repo> mUpdateRepos = new ArrayList<>();
private List<Repo> mInstalledRepos = new ArrayList<>();
private List<Repo> mOthersRepos = new ArrayList<>();
private List<Repo> fUpdateRepos = new ArrayList<>();
private List<Repo> fInstalledRepos = new ArrayList<>();
private List<Repo> 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<SimpleSectionedRecyclerViewAdapter.Section> 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);
}

View File

@ -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<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
Utils.createFile("/magisk/.core/magiskhide/enable");
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
} else {
new AsyncTask<Void, Void, Void>() {
@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":

View File

@ -60,7 +60,7 @@ public class Module extends BaseModule {
new AsyncTask<Void, Void, Void>() {
@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<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
mRemove = !Utils.removeFile(mRemoveFile);
mRemove = !Utils.removeItem(mRemoveFile);
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);

View File

@ -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;

View File

@ -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));
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_save"

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/repo_search"
app:actionViewClass="android.widget.SearchView"
app:showAsAction="always"/>
</menu>

View File

@ -98,6 +98,8 @@
<string name="settings_developer_logging_summary">Check this to enable more verbose logging.</string>
<string name="settings_shell_logging_title">Enable shell command debug logging</string>
<string name="settings_shell_logging_summary">Check this to enable logging all shell commands and output</string>
<string name="settings_magiskhide_title">Enable Magisk Hide</string>
<string name="settings_magiskhide_summary">Reboot to apply settings</string>
<!-- Strings related to Settings -->

View File

@ -12,6 +12,17 @@
android:entries="@array/themes"
android:entryValues="@array/themes"/>
</PreferenceCategory>
<PreferenceCategory
android:title="Magisk">
<CheckBoxPreference
android:key="magiskhide"
android:defaultValue="false"
android:title="@string/settings_magiskhide_title"
android:summary="@string/settings_magiskhide_summary" />
<CheckBoxPreference
android:key="busybox"
android:defaultValue="false"

View File

@ -6,7 +6,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.android.tools.build:gradle:2.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files