diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java new file mode 100644 index 000000000..417f8fc3e --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java @@ -0,0 +1,47 @@ +package com.topjohnwu.magisk; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.topjohnwu.magisk.module.Module; +import com.topjohnwu.magisk.module.Repo; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public abstract class BaseRepoFragment extends Fragment { + + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + @BindView(R.id.empty_rv) + TextView emptyTv; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.single_module_fragment, container, false); + ButterKnife.bind(this, view); + + if (listRepos().size() == 0) { + emptyTv.setVisibility(View.VISIBLE); + recyclerView.setVisibility(View.GONE); + + return view; + } + + recyclerView.setAdapter(new ReposAdapter(listRepos()) { + + }); + return view; + } + + protected abstract List listRepos(); +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java index ff25635ad..c5b015f4c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java @@ -5,12 +5,10 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; -import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TextView; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.module.ModuleRepo; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 4d2cbd1f9..d65cc7493 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -22,7 +22,7 @@ import android.view.ViewGroup; import android.widget.ProgressBar; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.module.ModuleRepo; +import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.utils.Utils; import java.io.File; @@ -36,7 +36,7 @@ public class ModulesFragment extends Fragment { public static List listModules = new ArrayList<>(); public static List listModulesCache = new ArrayList<>(); - public static List listModulesDownload = new ArrayList<>(); + public static List listModulesDownload = new ArrayList<>(); private static final int FILE_SELECT_CODE = 0; private File input; @@ -50,9 +50,8 @@ public class ModulesFragment extends Fragment { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.modules_fragment, container, false); ButterKnife.bind(this, view); - + new Utils.LoadModules(getContext()).execute(); new updateUI().execute(); - setHasOptionsMenu(true); return view; } @@ -125,10 +124,10 @@ public class ModulesFragment extends Fragment { } } - public static class DownloadModuleFragment extends BaseModuleFragment { + public static class DownloadModuleFragment extends BaseRepoFragment { @Override - protected List listModules() { + protected List listRepos() { return listModulesDownload; } @@ -180,7 +179,6 @@ public class ModulesFragment extends Fragment { } else if (position == 1) { return new CacheModuleFragment(); } else { - Log.d("Magisk","DL Fragment picked here"); return new DownloadModuleFragment(); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java new file mode 100644 index 000000000..a07eed510 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -0,0 +1,94 @@ +package com.topjohnwu.magisk; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.TextView; + +import com.topjohnwu.magisk.module.Module; +import com.topjohnwu.magisk.module.Repo; +import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.Utils; + +import java.io.File; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class ReposAdapter extends RecyclerView.Adapter { + + private final List mList; + private View view; + private Context context; + + public ReposAdapter(List list) { + this.mList = list; + + } + + + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false); + context = parent.getContext(); + + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(final ViewHolder holder, int position) { + final Repo repo = mList.get(position); + + holder.title.setText(repo.getName()); + holder.versionName.setText(repo.getVersion()); + holder.description.setText(repo.getDescription()); + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + Utils.DownloadReceiver reciever = new Utils.DownloadReceiver() { + @Override + public void task(File file) { + Log.d("Magisk","Task firing"); + new Utils.FlashZIP(context,repo.getName(),file.toString()).execute(); + } + }; + String filename = repo.getName().replace(" ","") + ".zip"; + Utils.downloadAndReceive(context,reciever,repo.getZipUrl(),filename); + + } + }); + + + } + + + + + @Override + public int getItemCount() { + return mList.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.title) TextView title; + + @BindView(R.id.version_name) TextView versionName; + @BindView(R.id.description) TextView description; + + + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} \ No newline at end of file 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 6cfd62971..51e3736bb 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -1,14 +1,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; -import java.io.File; -import java.io.FileReader; - public class Module { private String mRemoveFile; @@ -17,6 +10,7 @@ public class Module { private String mName = null; private String mVersion = "(No version provided)"; private String mDescription = "(No description provided)"; + private String mUrl = null; private boolean mEnable; private boolean mRemove; @@ -24,7 +18,6 @@ public class Module { private String mId; private int mVersionCode; - public Module(String path) { mRemoveFile = path + "/remove"; mDisableFile = path + "/disable"; @@ -74,25 +67,21 @@ public class Module { } - public Module(ModuleRepo.Repo repo) { - - - - mName = repo.getName(); - mVersion = repo.getVersion(); - mDescription = repo.getDescription(); - mId = "foo"; - mVersionCode = 111; - - - - + public Module(Repo repo) { + mName = repo.getName(); + mVersion = repo.getVersion(); + mDescription = repo.getDescription(); + mId = "foo"; + mVersionCode = 111; + mUrl = repo.getZipUrl(); mEnable = true; mRemove = false; } + + public String getName() { return mName; } diff --git a/app/src/main/java/com/topjohnwu/magisk/module/ModuleRepo.java b/app/src/main/java/com/topjohnwu/magisk/module/ModuleRepo.java deleted file mode 100644 index ed564dc9f..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/module/ModuleRepo.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.topjohnwu.magisk.module; - -import android.app.ListActivity; -import android.content.Context; -import android.os.AsyncTask; -import android.os.Bundle; -import android.util.Log; - -import com.topjohnwu.magisk.utils.WebRequest; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -public class ModuleRepo { - private String[] result; - private static String url = "https://api.github.com/orgs/Magisk-Modules-Repo/repos"; - private static List repos = new ArrayList(); - private static final String TAG_ID = "id"; - private static final String TAG_NAME = "name"; - private Context activityContext; - - - public List listRepos() { - MyAsyncTask asynchTask = new MyAsyncTask(); - Log.d("Magisk", "Gitagent init called"); - asynchTask.execute(); - List out = null; - - - - return repos; - } - - public JSONArray fetchModuleArray() { - fetchRepoInfo(); - parseRepoInfo(); - JSONArray moduleArray = enumerateModules(); - return null; - } - - private void fetchRepoInfo() { - - } - - private void parseRepoInfo() { - - } - - private JSONArray enumerateModules() { - JSONArray enumeratedModules = new JSONArray(); - return enumeratedModules; - } - - class MyAsyncTask extends AsyncTask { - - @Override - protected void onPreExecute() { - super.onPreExecute(); - - - } - - @Override - protected Void doInBackground(String... params) { - Log.d("Magisk", "doInBackground running"); - // Creating service handler class instance - WebRequest webreq = new WebRequest(); - - // Making a request to url and getting response - String jsonStr = webreq.makeWebServiceCall(url, WebRequest.GET); - - Log.d("Response: ", "> " + jsonStr); - - try { - repos.clear(); - JSONArray jsonArray = new JSONArray(jsonStr); - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject jsonobject = jsonArray.getJSONObject(i); - String name = jsonobject.getString("name"); - String urlString = jsonobject.getString("html_url"); - try { - URL url = new URL(urlString); - if (!name.contains("Repo.github.io")) { - repos.add(new Repo(name, url)); - } - } catch (MalformedURLException e) { - e.printStackTrace(); - } - - } - for (int i = 0; i < repos.size(); i++) { - Repo repo = repos.get(i); - Log.d("Magisk", repo.name + " URL: " + repo.url); - - } - } catch (JSONException e) { - e.printStackTrace(); - } - - - return null; - - - } - - protected void onPostExecute(Void v) { - - - } // protected void onPostExecute(Void v) - } //class MyAsyncTask extends AsyncTask - - protected void onPreExecute() { - - } - - public class Repo { - public String name; - public URL url; - public String manifest, version, moduleName, moduleDescription, moduleAuthor, moduleAuthorUrl; - public Boolean usesRoot,usesXposed; - - - public Repo(String name, URL url) { - this.name = name; - this.url = url; - this.manifest = ("https://raw.githubusercontent.com/Magisk-Modules-Repo/" + name + "/master/module.json"); - WebRequest webreq = new WebRequest(); - - // Making a request to url and getting response - String manifestString = webreq.makeWebServiceCall(manifest, WebRequest.GET); - Log.d("Magisk","Inner fetch: " + manifestString); - try { - JSONObject jsonobject = new JSONObject(manifestString); - Log.d("Magisk","Object: " +jsonobject.toString()); - version = jsonobject.getString("versionCode"); - moduleName = jsonobject.getString("moduleName"); - moduleDescription = jsonobject.getString("moduleDescription"); - moduleAuthor = jsonobject.getString("moduleAuthor"); - moduleAuthorUrl = jsonobject.getString("authorUrl"); - usesRoot = Boolean.getBoolean(jsonobject.getString("usesRoot")); - usesXposed = Boolean.getBoolean(jsonobject.getString("usesXposed")); - - } catch (JSONException e) { - e.printStackTrace(); - } - - Log.d("Magisk","We're in! " + " " + version + " " + moduleName + " " + moduleAuthor + " " + moduleDescription + " " + moduleAuthorUrl); - - } - - public String getName() { - return moduleName; - } - - public String getVersion() { - return version; - } - - public String getDescription() { - return moduleDescription; - } - } - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java new file mode 100644 index 000000000..92bd6a1d4 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -0,0 +1,112 @@ +package com.topjohnwu.magisk.module; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.topjohnwu.magisk.utils.WebRequest; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashSet; +import java.util.Set; + +public class Repo { + public String name; + public String baseUrl, zipUrl,manifestUrl, logUrl; + public String manifest, version, moduleName, moduleDescription, moduleAuthor, moduleAuthorUrl; + public Boolean usesRoot,usesXposed; + private Context appContext; + private SharedPreferences prefs; + + + public Repo(String name, String url, Context context) { + appContext = context; + this.name = name; + this.baseUrl = url; + prefs = PreferenceManager.getDefaultSharedPreferences(appContext); + + } + + public Repo(String moduleName, String moduleDescription, String zipUrl) { + this.zipUrl = zipUrl; + this.moduleDescription = moduleDescription; + this.moduleName = moduleName; + prefs = PreferenceManager.getDefaultSharedPreferences(appContext); + } + + public void fetch() { + + WebRequest webreq = new WebRequest(); + // Construct initial url for contents + Log.d("Magisk","Manifest string is: " + baseUrl + "/contents/"); + String repoString = webreq.makeWebServiceCall(baseUrl + "/contents/", WebRequest.GET); + + try { + JSONArray repoArray = new JSONArray(repoString); + + for (int f = 0; f < repoArray.length(); f++) { + JSONObject jsonobject = repoArray.getJSONObject(f); + String name = jsonobject.getString("name"); + if (name.contains(".zip")) { + this.zipUrl = jsonobject.getString("download_url"); + } else if (name.equals("module.json")) { + this.manifestUrl = jsonobject.getString("download_url"); + } else if (name.equals("Changelog.txt")) { + this.logUrl = jsonobject.getString("download_url"); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + + Log.d("Magisk","Inner fetch: " + repoString); + try { + WebRequest jsonReq = new WebRequest(); + // Construct initial url for contents + String manifestString = webreq.makeWebServiceCall(this.manifestUrl, WebRequest.GET); + JSONObject manifestObject = new JSONObject(manifestString); + Log.d("Magisk","Object: " +manifestObject.toString()); + version = manifestObject.getString("versionCode"); + moduleName = manifestObject.getString("moduleName"); + moduleDescription = manifestObject.getString("moduleDescription"); + moduleAuthor = manifestObject.getString("moduleAuthor"); + usesRoot = Boolean.getBoolean(manifestObject.getString("usesRoot")); + usesXposed = Boolean.getBoolean(manifestObject.getString("usesXposed")); + SharedPreferences.Editor editor = prefs.edit(); + String prefsString = "[{\"moduleDescription\":\"" + moduleDescription + "\"," + + "\"moduleName\":\"" + moduleName + "\"," + + "\"moduleAuthor\":\"" + moduleAuthor + "\"," + + "\"moduleAuthorUrl\":\"" + moduleAuthorUrl + "\"," + + "\"usesRoot\":\"" + usesRoot + "\"," + + "\"usesXposed\":\"" + usesXposed + "\"," + + "\"zipUrl\":\"" + zipUrl + "\"," + + "\"logUrl\":\"" + logUrl + "\"}]"; + editor.putString("module_" + moduleName,prefsString); + editor.putBoolean("hasCachedRepos",true); + editor.apply(); + + } catch (JSONException e) { + e.printStackTrace(); + } + + } + + public String getName() { + return moduleName; + } + + public String getVersion() { + return version; + } + public String getLogUrl() { + return logUrl; + } + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java new file mode 100644 index 000000000..97ebf2810 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java @@ -0,0 +1,130 @@ +package com.topjohnwu.magisk.module; + +import android.app.ListActivity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.topjohnwu.magisk.utils.WebRequest; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class RepoAdapter { + private String[] result; + private static String url = "https://api.github.com/orgs/Magisk-Modules-Repo/repos"; + private static List repos = new ArrayList(); + private static final String TAG_ID = "id"; + private static final String TAG_NAME = "name"; + private Context activityContext; + + + public List listRepos(Context context) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (!prefs.contains("hasCachedRepos")) { + activityContext = context; + MyAsyncTask asynchTask = new MyAsyncTask(); + asynchTask.execute(); + List out = null; + } else { + Log.d("Magisk", "Building from cache"); + Map map = prefs.getAll(); + for (Map.Entry entry : map.entrySet()) + { + if (entry.getKey().contains("module_")) { + String repoString = entry.getValue().toString(); + JSONArray repoArray = null; + try { + repoArray = new JSONArray(repoString); + + repos.clear(); + for (int f = 0; f < repoArray.length(); f++) { + JSONObject jsonobject = repoArray.getJSONObject(f); + String name = jsonobject.getString("name"); + String moduleName, moduleDescription, zipUrl; + moduleName = jsonobject.getString("moduleName"); + moduleDescription = jsonobject.getString("moduleDescription"); + zipUrl = jsonobject.getString("zipUrl"); + repos.add(new Repo(moduleName,moduleDescription,zipUrl)); + + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + System.out.println(entry.getKey() + "/" + entry.getValue()); + } + + } + + + return repos; + } + + + + class MyAsyncTask extends AsyncTask { + + @Override + protected void onPreExecute() { + super.onPreExecute(); + + + } + + @Override + protected Void doInBackground(String... params) { + Log.d("Magisk", "doInBackground running"); + // Creating service handler class instance + WebRequest webreq = new WebRequest(); + + // Making a request to url and getting response + String jsonStr = webreq.makeWebServiceCall(url, WebRequest.GET); + + Log.d("Response: ", "> " + jsonStr); + + try { + repos.clear(); + JSONArray jsonArray = new JSONArray(jsonStr); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonobject = jsonArray.getJSONObject(i); + String name = jsonobject.getString("name"); + String url = jsonobject.getString("url"); + if (!name.contains("Repo.github.io")) { + repos.add(new Repo(name, url, activityContext)); + } + for (int f = 0; f < repos.size(); f++) { + repos.get(f).fetch(); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + return null; + + + } + + protected void onPostExecute(Void v) { + + + } // protected void onPostExecute(Void v) + } //class MyAsyncTask extends AsyncTask + + protected void onPreExecute() { + + } + + + +} 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 6a6e136f7..3e8c619ba 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -8,11 +8,13 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Environment; +import android.preference.PreferenceManager; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; @@ -23,7 +25,8 @@ import android.widget.Toast; import com.topjohnwu.magisk.ModulesFragment; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.module.ModuleRepo; +import com.topjohnwu.magisk.module.RepoAdapter; +import com.topjohnwu.magisk.module.Repo; import org.json.JSONException; import org.json.JSONObject; @@ -376,8 +379,9 @@ public class Utils { List magisk = getModList(MAGISK_PATH); Log.d("Magisk", String.valueOf(magisk)); List magiskCache = getModList(MAGISK_CACHE_PATH); - ModuleRepo mr = new ModuleRepo(); - List magiskRepos = mr.listRepos(); + RepoAdapter mr = new RepoAdapter(); + + List magiskRepos = mr.listRepos(mContext); for (String mod : magisk) { Log.d("Magisk","Utils, listing modules " + mod); ModulesFragment.listModules.add(new Module(mod)); @@ -385,8 +389,8 @@ public class Utils { for (String mod : magiskCache) { ModulesFragment.listModulesCache.add(new Module(mod)); } - for (ModuleRepo.Repo repo : magiskRepos) { - ModulesFragment.listModulesDownload.add(new Module(repo)); + for (Repo repo : magiskRepos) { + ModulesFragment.listModulesDownload.add(repo); } return null; @@ -424,6 +428,7 @@ public class Utils { "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" ); + Log.d("Magisk","ZipResult: " + ret.toString()); return Boolean.parseBoolean(ret.get(ret.size() -1)); } } diff --git a/app/src/main/res/layout/list_item_repo.xml b/app/src/main/res/layout/list_item_repo.xml new file mode 100644 index 000000000..353a08fc9 --- /dev/null +++ b/app/src/main/res/layout/list_item_repo.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file