mirror of
				https://github.com/topjohnwu/Magisk.git
				synced 2025-10-31 08:44:07 +00:00 
			
		
		
		
	Add search bar & Magisk Hide option
This commit is contained in:
		| @@ -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(); | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
|   | ||||
| @@ -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": | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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)); | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										9
									
								
								app/src/main/res/menu/menu_repo.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/menu/menu_repo.xml
									
									
									
									
									
										Normal 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> | ||||
| @@ -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 --> | ||||
|  | ||||
|   | ||||
| @@ -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" | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 topjohnwu
					topjohnwu