From aee3bd3a806828a5038219b26c133b4ac367730c Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Thu, 1 Sep 2016 10:42:26 -0500 Subject: [PATCH 01/27] Fix FAB layout error --- .../com/topjohnwu/magisk/ModulesFragment.java | 2 ++ app/src/main/res/layout/modules_fragment.xml | 27 ++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 4f87f4e64..a67b47c6e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -70,6 +70,8 @@ public class ModulesFragment extends Fragment { intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(intent,FILE_SELECT_CODE); } + + }); } diff --git a/app/src/main/res/layout/modules_fragment.xml b/app/src/main/res/layout/modules_fragment.xml index 0f9714854..7c954d6a2 100644 --- a/app/src/main/res/layout/modules_fragment.xml +++ b/app/src/main/res/layout/modules_fragment.xml @@ -1,6 +1,13 @@ + + android:layout_height="match_parent" /> - \ No newline at end of file + + + + + + \ No newline at end of file From 4f62320e7bd5008b2bdac185a7043407e4b9167c Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Thu, 1 Sep 2016 10:42:37 -0500 Subject: [PATCH 02/27] Temp disable busybox install for testing --- .../com/topjohnwu/magisk/utils/Utils.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) 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 c36710f21..515bba62f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -156,19 +156,19 @@ public class Utils { } // 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" - ); - } +// 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; } From 0e23935455797f7994eb4f3bd480cf2bee616e15 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Thu, 1 Sep 2016 16:58:26 -0500 Subject: [PATCH 03/27] Add some internets! WIP, not done yet. --- .../com/topjohnwu/magisk/ModulesAdapter.java | 1 + .../com/topjohnwu/magisk/ModulesFragment.java | 25 ++- .../com/topjohnwu/magisk/module/Module.java | 19 ++ .../topjohnwu/magisk/module/ModuleRepo.java | 170 ++++++++++++++++++ .../com/topjohnwu/magisk/utils/Utils.java | 11 ++ .../topjohnwu/magisk/utils/WebRequest.java | 105 +++++++++++ 6 files changed, 326 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/module/ModuleRepo.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java index f5cf729f1..ff25635ad 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java @@ -10,6 +10,7 @@ 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 a67b47c6e..4d2cbd1f9 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -12,6 +12,7 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; +import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -21,14 +22,12 @@ import android.view.ViewGroup; import android.widget.ProgressBar; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.module.ModuleRepo; import com.topjohnwu.magisk.utils.Utils; import java.io.File; -import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutionException; import butterknife.BindView; import butterknife.ButterKnife; @@ -37,6 +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<>(); private static final int FILE_SELECT_CODE = 0; private File input; @@ -73,6 +73,7 @@ public class ModulesFragment extends Fragment { }); + } public void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -95,6 +96,7 @@ public class ModulesFragment extends Fragment { case R.id.force_reload: listModules.clear(); listModulesCache.clear(); + listModulesDownload.clear(); progressBar.setVisibility(View.VISIBLE); viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); @@ -123,6 +125,15 @@ public class ModulesFragment extends Fragment { } } + public static class DownloadModuleFragment extends BaseModuleFragment { + + @Override + protected List listModules() { + return listModulesDownload; + } + + } + private class updateUI extends AsyncTask { @@ -145,7 +156,7 @@ public class ModulesFragment extends Fragment { private class TabsAdapter extends FragmentPagerAdapter { String[] tabTitles = new String[]{ - getString(R.string.modules), getString(R.string.cache_modules) + getString(R.string.modules), getString(R.string.cache_modules) ,"Download" }; public TabsAdapter(FragmentManager fm) { @@ -166,9 +177,13 @@ public class ModulesFragment extends Fragment { public Fragment getItem(int position) { if (position == 0) { return new NormalModuleFragment(); - } else { + } 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/module/Module.java b/app/src/main/java/com/topjohnwu/magisk/module/Module.java index 74afbe3ab..6cfd62971 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -74,6 +74,25 @@ public class Module { } + public Module(ModuleRepo.Repo repo) { + + + + mName = repo.getName(); + mVersion = repo.getVersion(); + mDescription = repo.getDescription(); + mId = "foo"; + mVersionCode = 111; + + + + + + 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 new file mode 100644 index 000000000..ed564dc9f --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/module/ModuleRepo.java @@ -0,0 +1,170 @@ +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/utils/Utils.java b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java index 515bba62f..6a6e136f7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -16,12 +16,14 @@ import android.os.Environment; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; +import android.util.Log; 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 com.topjohnwu.magisk.module.ModuleRepo; import org.json.JSONException; import org.json.JSONObject; @@ -370,14 +372,23 @@ public class Utils { protected Void doInBackground(Void... voids) { ModulesFragment.listModules.clear(); ModulesFragment.listModulesCache.clear(); + ModulesFragment.listModulesDownload.clear(); 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(); for (String mod : magisk) { + Log.d("Magisk","Utils, listing modules " + mod); ModulesFragment.listModules.add(new Module(mod)); } for (String mod : magiskCache) { ModulesFragment.listModulesCache.add(new Module(mod)); } + for (ModuleRepo.Repo repo : magiskRepos) { + ModulesFragment.listModulesDownload.add(new Module(repo)); + } + return null; } } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java b/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java new file mode 100644 index 000000000..1b782a158 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java @@ -0,0 +1,105 @@ +package com.topjohnwu.magisk.utils; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; + +import javax.net.ssl.HttpsURLConnection; + +public class WebRequest { + + static String response = null; + public final static int GET = 1; + public final static int POST = 2; + + //Constructor with no parameter + public WebRequest() { + + } + + /** + * Making web service call + * + * @url - url to make request + * @requestmethod - http request method + */ + public String makeWebServiceCall(String url, int requestmethod) { + return this.makeWebServiceCall(url, requestmethod, null); + } + + /** + * Making service call + * + * @url - url to make request + * @requestmethod - http request method + * @params - http request params + */ + public String makeWebServiceCall(String urladdress, int requestmethod, + HashMap params) { + URL url; + String response = ""; + try { + url = new URL(urladdress); + + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setReadTimeout(15000); + conn.setConnectTimeout(15000); + conn.setDoInput(true); + + if (requestmethod == POST) { + conn.setRequestMethod("POST"); + } else if (requestmethod == GET) { + conn.setRequestMethod("GET"); + } + + if (params != null) { + OutputStream os = conn.getOutputStream(); + BufferedWriter writer = new BufferedWriter( + new OutputStreamWriter(os, "UTF-8")); + + StringBuilder result = new StringBuilder(); + boolean first = true; + for (Map.Entry entry : params.entrySet()) { + if (first) + first = false; + else + result.append("&"); + + result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); + result.append("="); + result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); + } + + writer.write(result.toString()); + + writer.flush(); + writer.close(); + os.close(); + } + + int responseCode = conn.getResponseCode(); + + if (responseCode == HttpsURLConnection.HTTP_OK) { + String line; + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + while ((line = br.readLine()) != null) { + response += line; + } + } else { + response = ""; + } + } catch (Exception e) { + e.printStackTrace(); + } + + return response; + } + +} \ No newline at end of file From ffedb79670e85a5629d93af43dcff54ba6949d07 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Fri, 2 Sep 2016 08:32:34 -0500 Subject: [PATCH 04/27] Synch update - WIP Not finished, just synchronizing workflows. --- .../topjohnwu/magisk/BaseRepoFragment.java | 47 +++++ .../com/topjohnwu/magisk/ModulesAdapter.java | 2 - .../com/topjohnwu/magisk/ModulesFragment.java | 12 +- .../com/topjohnwu/magisk/ReposAdapter.java | 94 ++++++++++ .../com/topjohnwu/magisk/module/Module.java | 31 ++-- .../topjohnwu/magisk/module/ModuleRepo.java | 170 ------------------ .../com/topjohnwu/magisk/module/Repo.java | 112 ++++++++++++ .../topjohnwu/magisk/module/RepoAdapter.java | 130 ++++++++++++++ .../com/topjohnwu/magisk/utils/Utils.java | 15 +- app/src/main/res/layout/list_item_repo.xml | 64 +++++++ 10 files changed, 472 insertions(+), 205 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java delete mode 100644 app/src/main/java/com/topjohnwu/magisk/module/ModuleRepo.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/module/Repo.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java create mode 100644 app/src/main/res/layout/list_item_repo.xml 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 From 8dfe0f437326fa1e28b559410da1ae1bf9c5c675 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Fri, 2 Sep 2016 08:36:03 -0500 Subject: [PATCH 05/27] I must have been really tired... Not sure how this got deleted... --- .../main/java/com/topjohnwu/magisk/module/Repo.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index 92bd6a1d4..ea35ca871 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -101,7 +101,16 @@ public class Repo { public String getVersion() { return version; - } + } + + public String getDescription() { + return moduleDescription; + } + + public String getZipUrl() { + return zipUrl; + } + public String getLogUrl() { return logUrl; } From aa991b62f40f2f964f08373700e7c06a7ce0fe44 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Fri, 2 Sep 2016 13:18:37 -0500 Subject: [PATCH 06/27] My brain hurts... --- .../topjohnwu/magisk/BaseModuleFragment.java | 45 ++++++++++++- .../topjohnwu/magisk/BaseRepoFragment.java | 23 ++++++- .../com/topjohnwu/magisk/ModulesFragment.java | 11 +++- .../com/topjohnwu/magisk/ReposAdapter.java | 27 +++++--- .../com/topjohnwu/magisk/WelcomeActivity.java | 6 +- .../com/topjohnwu/magisk/module/Module.java | 18 +++++- .../com/topjohnwu/magisk/module/Repo.java | 41 +++++++----- .../com/topjohnwu/magisk/utils/Utils.java | 64 ++++++++++++++++--- .../res/layout/single_module_fragment.xml | 13 ++-- 9 files changed, 199 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index 9a01bfa7f..739ec0463 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -1,10 +1,14 @@ package com.topjohnwu.magisk; +import android.content.SharedPreferences; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,6 +19,7 @@ import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.utils.Utils; import java.util.List; +import java.util.concurrent.ExecutionException; import butterknife.BindView; import butterknife.ButterKnife; @@ -23,13 +28,30 @@ public abstract class BaseModuleFragment extends Fragment { @BindView(R.id.recyclerView) RecyclerView recyclerView; @BindView(R.id.empty_rv) TextView emptyTv; - + private SwipeRefreshLayout mSwipeRefreshLayout; + private View view; + private SharedPreferences prefs; @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); + view = inflater.inflate(R.layout.single_module_fragment, container, false); + mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefreshLayout); + mSwipeRefreshLayout.setOnRefreshListener(() -> { + refreshItems(); + }); + ButterKnife.bind(this, view); + prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + prefs.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + if (s.contains("updated")) { + view.invalidate(); + view.requestLayout(); + + } + } + }); if (listModules().size() == 0) { emptyTv.setVisibility(View.VISIBLE); recyclerView.setVisibility(View.GONE); @@ -62,5 +84,22 @@ public abstract class BaseModuleFragment extends Fragment { return view; } + void refreshItems() { + Log.d("Magisk", "Calling refreshitems for online"); + Utils.LoadModules utils = new Utils.LoadModules(getActivity(),true); + utils.execute(); + onItemsLoadComplete(); + view.requestLayout(); + } + + + void onItemsLoadComplete() { + // Update the adapter and notify data set changed + // ... + + // Stop refresh animation + mSwipeRefreshLayout.setRefreshing(false); + } + protected abstract List listModules(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java index 417f8fc3e..a60bd1043 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java @@ -3,7 +3,9 @@ package com.topjohnwu.magisk; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,6 +13,7 @@ import android.widget.TextView; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.Repo; +import com.topjohnwu.magisk.utils.Utils; import java.util.List; @@ -23,11 +26,16 @@ public abstract class BaseRepoFragment extends Fragment { RecyclerView recyclerView; @BindView(R.id.empty_rv) TextView emptyTv; - + private SwipeRefreshLayout mSwipeRefreshLayout; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.single_module_fragment, container, false); + mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefreshLayout); + mSwipeRefreshLayout.setOnRefreshListener(() -> { + refreshItems(); + }); + ButterKnife.bind(this, view); if (listRepos().size() == 0) { @@ -43,5 +51,18 @@ public abstract class BaseRepoFragment extends Fragment { return view; } + void refreshItems() { + Log.d("Magisk", "Calling refreshitems for online"); + new Utils.LoadModules(getActivity(),true).execute(); + onItemsLoadComplete(); + } + + void onItemsLoadComplete() { + // Update the adapter and notify data set changed + // ... + + // Stop refresh animation + mSwipeRefreshLayout.setRefreshing(false); + } protected abstract List listRepos(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index d65cc7493..3ab89fcc1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -2,9 +2,11 @@ package com.topjohnwu.magisk; import android.app.Activity; import android.content.Intent; +import android.content.SharedPreferences; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.TabLayout; @@ -50,7 +52,12 @@ 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(); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + if (prefs.contains("hasCachedRepos")) { + new Utils.LoadModules(getActivity(), false).execute(); + } else { + new Utils.LoadModules(getActivity(), true).execute(); + } new updateUI().execute(); setHasOptionsMenu(true); return view; @@ -99,7 +106,7 @@ public class ModulesFragment extends Fragment { progressBar.setVisibility(View.VISIBLE); viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); - new Utils.LoadModules(getContext()).execute(); + new Utils.LoadModules(getActivity(),false).execute(); new updateUI().execute(); break; } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java index a07eed510..f543e7d29 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -1,6 +1,8 @@ package com.topjohnwu.magisk; import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; @@ -9,6 +11,7 @@ import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.TextView; +import android.widget.Toast; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.Repo; @@ -52,17 +55,21 @@ public class ReposAdapter extends RecyclerView.Adapter view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (!prefs.contains("isInstalled_" + repo.getName())) { - 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); - + 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); + } else { + Toast.makeText(context,repo.getName() + " is already installed.",Toast.LENGTH_SHORT).show(); + } } }); diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java index a7b1a9377..6d34d7cfd 100644 --- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java @@ -1,6 +1,8 @@ package com.topjohnwu.magisk; import android.Manifest; +import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; @@ -28,6 +30,7 @@ import butterknife.ButterKnife; public class WelcomeActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { private static final String SELECTED_ITEM_ID = "SELECTED_ITEM_ID"; + private Context mContext; private final Handler mDrawerHandler = new Handler(); @@ -55,7 +58,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView } new Utils.Initialize(this).execute(); new Utils.CheckUpdates(this).execute(); - new Utils.LoadModules(this).execute(); + new Utils.LoadModules(getApplication(),false).execute(); setSupportActionBar(toolbar); @@ -88,6 +91,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView } + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); 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 51e3736bb..c46998f08 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -1,7 +1,14 @@ 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.Utils; +import java.util.Map; + public class Module { private String mRemoveFile; @@ -18,7 +25,16 @@ public class Module { private String mId; private int mVersionCode; - public Module(String path) { + public Module(String path, Context context) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + Map keys = prefs.getAll(); + + for(Map.Entry entry : keys.entrySet()){ + + if(entry.getValue().toString().contains(path)) { + Log.d("Magisk", "Hey, look a matching path, this guy's name is " + entry.getKey().replace("path_","")); + } + } mRemoveFile = path + "/remove"; mDisableFile = path + "/disable"; for (String line : Utils.readFile(path + "/module.prop")) { diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index ea35ca871..228e7809c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -11,38 +11,43 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.util.HashSet; -import java.util.Set; +import java.text.SimpleDateFormat; +import java.util.Date; public class Repo { public String name; - public String baseUrl, zipUrl,manifestUrl, logUrl; - public String manifest, version, moduleName, moduleDescription, moduleAuthor, moduleAuthorUrl; - public Boolean usesRoot,usesXposed; + public String baseUrl, zipUrl, manifestUrl, logUrl, manifest, version, moduleName, moduleDescription, moduleAuthor, moduleAuthorUrl; + public Date lastUpdate; + public Boolean usesRoot, usesXposed; private Context appContext; private SharedPreferences prefs; - public Repo(String name, String url, Context context) { + public Repo(String name, String url, Date updated, Context context) { appContext = context; this.name = name; this.baseUrl = url; - prefs = PreferenceManager.getDefaultSharedPreferences(appContext); + this.lastUpdate = updated; + this.fetch(); } - public Repo(String moduleName, String moduleDescription, String zipUrl) { + public Repo(String moduleName, String moduleDescription, String zipUrl, Date lastUpdated, Context context) { + Log.d("Magisk", "Hey, I'm a repo! My name is " + moduleName); + appContext = context; this.zipUrl = zipUrl; this.moduleDescription = moduleDescription; this.moduleName = moduleName; - prefs = PreferenceManager.getDefaultSharedPreferences(appContext); + this.lastUpdate = lastUpdated; + + } public void fetch() { - + prefs = PreferenceManager.getDefaultSharedPreferences(appContext); WebRequest webreq = new WebRequest(); // Construct initial url for contents - Log.d("Magisk","Manifest string is: " + baseUrl + "/contents/"); + Log.d("Magisk", "Manifest string is: " + baseUrl + "/contents/"); String repoString = webreq.makeWebServiceCall(baseUrl + "/contents/", WebRequest.GET); try { @@ -63,13 +68,13 @@ public class Repo { e.printStackTrace(); } - Log.d("Magisk","Inner fetch: " + repoString); + 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()); + Log.d("Magisk", "Object: " + manifestObject.toString()); version = manifestObject.getString("versionCode"); moduleName = manifestObject.getString("moduleName"); moduleDescription = manifestObject.getString("moduleDescription"); @@ -84,9 +89,13 @@ public class Repo { + "\"usesRoot\":\"" + usesRoot + "\"," + "\"usesXposed\":\"" + usesXposed + "\"," + "\"zipUrl\":\"" + zipUrl + "\"," + + "\"lastUpdate\":\"" + lastUpdate + "\"," + "\"logUrl\":\"" + logUrl + "\"}]"; - editor.putString("module_" + moduleName,prefsString); - editor.putBoolean("hasCachedRepos",true); + editor.putString("module_" + moduleName, prefsString); + editor.putBoolean("hasCachedRepos", true); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss"); + editor.putString("updated", sdf.toString()); + Log.d("Magisk", "Storing Preferences: " + prefsString); editor.apply(); } catch (JSONException e) { @@ -116,6 +125,4 @@ public class Repo { } - - } \ No newline at end of file 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 3e8c619ba..ebe8a68aa 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -28,6 +28,7 @@ import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.RepoAdapter; import com.topjohnwu.magisk.module.Repo; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -37,17 +38,21 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.List; public class Utils { public static int magiskVersion, remoteMagiskVersion = -1, remoteAppVersion = -1; public static String magiskLink, magiskChangelog, appChangelog, appLink, phhLink, supersuLink; + private Context appContext; 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"); @@ -87,6 +92,10 @@ public class Utils { return ret; } + public Utils(Context context) { + appContext = context; + } + 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(); @@ -366,9 +375,14 @@ public class Utils { public static class LoadModules extends AsyncTask { private Context mContext; + private boolean doReload; - public LoadModules(Context context) { + public LoadModules(Context context, boolean reload) { + Log.d("Magisk", "LoadModules created, online is " + reload); mContext = context; + doReload = reload; + + } @Override @@ -377,17 +391,17 @@ public class Utils { ModulesFragment.listModulesCache.clear(); ModulesFragment.listModulesDownload.clear(); List magisk = getModList(MAGISK_PATH); - Log.d("Magisk", String.valueOf(magisk)); + Log.d("Magisk", "Reload called, online mode set to " + doReload); List magiskCache = getModList(MAGISK_CACHE_PATH); RepoAdapter mr = new RepoAdapter(); - List magiskRepos = mr.listRepos(mContext); + + List magiskRepos = mr.listRepos(mContext, doReload); for (String mod : magisk) { - Log.d("Magisk","Utils, listing modules " + mod); - ModulesFragment.listModules.add(new Module(mod)); + ModulesFragment.listModules.add(new Module(mod,mContext)); } for (String mod : magiskCache) { - ModulesFragment.listModulesCache.add(new Module(mod)); + ModulesFragment.listModulesCache.add(new Module(mod,mContext)); } for (Repo repo : magiskRepos) { ModulesFragment.listModulesDownload.add(repo); @@ -395,6 +409,11 @@ public class Utils { return null; } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + } } public static class FlashZIP extends AsyncTask { @@ -402,6 +421,7 @@ public class Utils { private String mPath, mName; private ProgressDialog progress; private Context mContext; + private List ret; public FlashZIP(Context context, String name, String path) { mContext = context; @@ -420,7 +440,7 @@ public class Utils { if (!Shell.rootAccess()) { return false; } else { - List ret = Shell.su( + ret = Shell.su( "rm -rf /data/tmp", "mkdir -p /data/tmp", "cp -af " + mPath + " /data/tmp/install.zip", @@ -428,7 +448,6 @@ 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)); } } @@ -441,6 +460,35 @@ public class Utils { if (!result) { Toast.makeText(mContext, mContext.getString(R.string.manual_install, mPath), Toast.LENGTH_LONG).show(); return; + } else { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); + String jsonString = prefs.getString("module_" + mName,""); + String retSplit[] = ret.toString().split("Using path:"); + String ret2Split[] = retSplit[1].split(","); + String ret3Split[] = ret2Split[0].split("/"); + String finalSplit = "/" + ret3Split[1] + "/" + ret3Split[2]; + Log.d("Magisk","Damn, all that work for one path " + finalSplit); + if (!jsonString.equals("")) { + + JSONArray repoArray = null; + try { + repoArray = new JSONArray(jsonString); + + + for (int f = 0; f < repoArray.length(); f++) { + JSONObject jsonobject = repoArray.getJSONObject(f); + String name = mName; + Boolean installed = true; + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("isInstalled_" + mName,true); + editor.putString("path_" + mName,finalSplit); + editor.apply(); + + } + } catch (JSONException e) { + e.printStackTrace(); + } + } } done(); } diff --git a/app/src/main/res/layout/single_module_fragment.xml b/app/src/main/res/layout/single_module_fragment.xml index 0b9aa8c9b..42363f378 100644 --- a/app/src/main/res/layout/single_module_fragment.xml +++ b/app/src/main/res/layout/single_module_fragment.xml @@ -1,9 +1,10 @@ - + - \ No newline at end of file + \ No newline at end of file From bef43617362239ca671351df7ee70b18f5055eda Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Fri, 2 Sep 2016 14:50:54 -0500 Subject: [PATCH 07/27] That's important too... --- .../topjohnwu/magisk/module/RepoAdapter.java | 83 +++++++++++-------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java index 97ebf2810..a18d77b13 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java @@ -1,12 +1,11 @@ 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 android.widget.Toast; import com.topjohnwu.magisk.utils.WebRequest; @@ -14,9 +13,10 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.net.MalformedURLException; -import java.net.URL; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Map; @@ -27,42 +27,48 @@ public class RepoAdapter { private static final String TAG_ID = "id"; private static final String TAG_NAME = "name"; private Context activityContext; + private Date updatedDate, currentDate; - - public List listRepos(Context context) { + public List listRepos(Context context, boolean refresh) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - if (!prefs.contains("hasCachedRepos")) { + if (!prefs.contains("hasCachedRepos") | refresh) { activityContext = context; - MyAsyncTask asynchTask = new MyAsyncTask(); - asynchTask.execute(); + new MyAsyncTask().execute(); List out = null; } else { Log.d("Magisk", "Building from cache"); - Map map = prefs.getAll(); - for (Map.Entry entry : map.entrySet()) - { + Map map = prefs.getAll(); + repos.clear(); + for (Map.Entry entry : map.entrySet()) { if (entry.getKey().contains("module_")) { - String repoString = entry.getValue().toString(); + String repoString = entry.getValue().toString().replace(""", "\""); 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)); - } + for (int f = 0; f < repoArray.length(); f++) { + JSONObject jsonobject = repoArray.getJSONObject(f); + String name = entry.getKey().replace("module_", ""); + name = name.replace(" ", ""); + String moduleName, moduleDescription, zipUrl; + moduleName = jsonobject.getString("moduleName"); + moduleDescription = jsonobject.getString("moduleDescription"); + zipUrl = jsonobject.getString("zipUrl"); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + try { + updatedDate = format.parse(jsonobject.getString("lastUpdate")); + } catch (ParseException e) { + e.printStackTrace(); + } + repos.add(new Repo(name, moduleDescription, zipUrl, updatedDate, activityContext)); + + } } catch (JSONException e) { e.printStackTrace(); } } - System.out.println(entry.getKey() + "/" + entry.getValue()); + } } @@ -72,26 +78,31 @@ public class RepoAdapter { } - class MyAsyncTask extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); + } + + @Override + protected void onProgressUpdate(String... values) { + super.onProgressUpdate(values); + Toast.makeText(activityContext, "Refreshing online modules", Toast.LENGTH_SHORT).show(); } @Override protected Void doInBackground(String... params) { - Log.d("Magisk", "doInBackground running"); + publishProgress(); // 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("Magisk", "doInBackground Running, String: " + jsonStr + " Url: " + url); - Log.d("Response: ", "> " + jsonStr); try { repos.clear(); @@ -100,11 +111,18 @@ public class RepoAdapter { 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(); + String lastUpdate = jsonobject.getString("updated_at"); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + try { + updatedDate = format.parse(lastUpdate); + + } catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (!name.contains("Repo.github.io")) { + repos.add(new Repo(name, url, updatedDate, activityContext)); } } } catch (JSONException e) { @@ -126,5 +144,4 @@ public class RepoAdapter { } - } From f404fe05706e08cb7b678b7799d0b38859818b00 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Tue, 6 Sep 2016 16:54:08 -0500 Subject: [PATCH 08/27] Break/Fix Wheeeeee --- .../topjohnwu/magisk/BaseModuleFragment.java | 53 ++-- .../topjohnwu/magisk/BaseRepoFragment.java | 26 +- .../com/topjohnwu/magisk/ModulesFragment.java | 37 ++- .../com/topjohnwu/magisk/ReposAdapter.java | 91 +++++-- .../com/topjohnwu/magisk/module/Module.java | 125 ++++++--- .../com/topjohnwu/magisk/module/Repo.java | 250 +++++++++++++----- .../topjohnwu/magisk/module/RepoAdapter.java | 52 ++-- .../magisk/utils/AnimationHelper.java | 58 ++++ .../com/topjohnwu/magisk/utils/GitAgent.java | 8 + .../com/topjohnwu/magisk/utils/Utils.java | 8 +- .../topjohnwu/magisk/utils/WebRequest.java | 11 +- app/src/main/res/drawable/ic_done_black.xml | 9 + app/src/main/res/layout/list_item_repo.xml | 24 +- .../res/layout/list_item_repo_expanded.xml | 67 +++++ .../res/layout/single_module_fragment.xml | 7 +- app/src/main/res/values/strings.xml | 3 + 16 files changed, 607 insertions(+), 222 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/AnimationHelper.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/GitAgent.java create mode 100644 app/src/main/res/drawable/ic_done_black.xml create mode 100644 app/src/main/res/layout/list_item_repo_expanded.xml diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index 739ec0463..e41a73df8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -6,9 +6,7 @@ import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; -import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -19,26 +17,24 @@ import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.utils.Utils; import java.util.List; -import java.util.concurrent.ExecutionException; import butterknife.BindView; import butterknife.ButterKnife; public abstract class BaseModuleFragment extends Fragment { - @BindView(R.id.recyclerView) RecyclerView recyclerView; - @BindView(R.id.empty_rv) TextView emptyTv; - private SwipeRefreshLayout mSwipeRefreshLayout; + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + @BindView(R.id.empty_rv) + TextView emptyTv; private View view; private SharedPreferences prefs; + @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { view = inflater.inflate(R.layout.single_module_fragment, container, false); - mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefreshLayout); - mSwipeRefreshLayout.setOnRefreshListener(() -> { - refreshItems(); - }); + ButterKnife.bind(this, view); prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); @@ -59,16 +55,19 @@ public abstract class BaseModuleFragment extends Fragment { return view; } - recyclerView.setAdapter(new ModulesAdapter(listModules(), (chk, position) -> { - // On Checkbox change listener - CheckBox chbox = (CheckBox) chk; + recyclerView.setAdapter(new ModulesAdapter(listModules(), new Utils.ItemClickListener() { + @Override + public void onItemClick(View chk, int position) { + // On Checkbox change listener + CheckBox chbox = (CheckBox) chk; - 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(); + if (!chbox.isChecked()) { + BaseModuleFragment.this.listModules().get(position).createDisableFile(); + Snackbar.make(chk, R.string.disable_file_created, Snackbar.LENGTH_SHORT).show(); + } else { + BaseModuleFragment.this.listModules().get(position).removeDisableFile(); + Snackbar.make(chk, R.string.disable_file_removed, Snackbar.LENGTH_SHORT).show(); + } } }, (deleteBtn, position) -> { // On delete button click listener @@ -84,22 +83,6 @@ public abstract class BaseModuleFragment extends Fragment { return view; } - void refreshItems() { - Log.d("Magisk", "Calling refreshitems for online"); - Utils.LoadModules utils = new Utils.LoadModules(getActivity(),true); - utils.execute(); - onItemsLoadComplete(); - view.requestLayout(); - } - - - void onItemsLoadComplete() { - // Update the adapter and notify data set changed - // ... - - // Stop refresh animation - mSwipeRefreshLayout.setRefreshing(false); - } protected abstract List listModules(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java index a60bd1043..bc7d49474 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java @@ -3,17 +3,14 @@ package com.topjohnwu.magisk; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; -import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.CardView; 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.TextView; -import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.Repo; -import com.topjohnwu.magisk.utils.Utils; import java.util.List; @@ -26,15 +23,14 @@ public abstract class BaseRepoFragment extends Fragment { RecyclerView recyclerView; @BindView(R.id.empty_rv) TextView emptyTv; - private SwipeRefreshLayout mSwipeRefreshLayout; + + + @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.single_module_fragment, container, false); - mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefreshLayout); - mSwipeRefreshLayout.setOnRefreshListener(() -> { - refreshItems(); - }); + ButterKnife.bind(this, view); @@ -51,18 +47,6 @@ public abstract class BaseRepoFragment extends Fragment { return view; } - void refreshItems() { - Log.d("Magisk", "Calling refreshitems for online"); - new Utils.LoadModules(getActivity(),true).execute(); - onItemsLoadComplete(); - } - void onItemsLoadComplete() { - // Update the adapter and notify data set changed - // ... - - // Stop refresh animation - mSwipeRefreshLayout.setRefreshing(false); - } protected abstract List listRepos(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 3ab89fcc1..0af544180 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -14,6 +14,7 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; +import android.support.v4.widget.SwipeRefreshLayout; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -40,7 +41,9 @@ public class ModulesFragment extends Fragment { public static List listModulesCache = new ArrayList<>(); public static List listModulesDownload = new ArrayList<>(); private static final int FILE_SELECT_CODE = 0; + private TabsAdapter ta; private File input; + private SwipeRefreshLayout mSwipeRefreshLayout; @BindView(R.id.progressBar) ProgressBar progressBar; @BindView(R.id.fab) FloatingActionButton fabio; @@ -51,6 +54,7 @@ public class ModulesFragment extends Fragment { @Override 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); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); if (prefs.contains("hasCachedRepos")) { @@ -58,11 +62,18 @@ public class ModulesFragment extends Fragment { } else { new Utils.LoadModules(getActivity(), true).execute(); } + new updateUI().execute(); setHasOptionsMenu(true); return view; } + public void updateThisShit() { + new Utils.LoadModules(getActivity(), true).execute(); + new updateUI().execute(); + setHasOptionsMenu(true); + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); @@ -82,6 +93,8 @@ public class ModulesFragment extends Fragment { } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case FILE_SELECT_CODE: @@ -104,9 +117,10 @@ public class ModulesFragment extends Fragment { listModulesCache.clear(); listModulesDownload.clear(); progressBar.setVisibility(View.VISIBLE); - viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); + ta = new TabsAdapter(getChildFragmentManager()); + viewPager.setAdapter(ta); tabLayout.setupWithViewPager(viewPager); - new Utils.LoadModules(getActivity(),false).execute(); + new Utils.LoadModules(getActivity(),true).execute(); new updateUI().execute(); break; } @@ -114,6 +128,19 @@ public class ModulesFragment extends Fragment { return super.onOptionsItemSelected(item); } + public void redrawLayout() { + listModules.clear(); + listModulesCache.clear(); + listModulesDownload.clear(); + progressBar.setVisibility(View.VISIBLE); + ta = new TabsAdapter(getChildFragmentManager()); + viewPager.setAdapter(ta); + tabLayout.setupWithViewPager(viewPager); + new Utils.LoadModules(getActivity(),false).execute(); + new updateUI().execute(); + + } + public static class NormalModuleFragment extends BaseModuleFragment { @Override @@ -141,7 +168,7 @@ public class ModulesFragment extends Fragment { } - private class updateUI extends AsyncTask { + public class updateUI extends AsyncTask { @Override protected Void doInBackground(Void... voids) { @@ -153,8 +180,8 @@ public class ModulesFragment extends Fragment { super.onPostExecute(v); progressBar.setVisibility(View.GONE); - - viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); + ta = new TabsAdapter(getChildFragmentManager()); + viewPager.setAdapter(ta); tabLayout.setupWithViewPager(viewPager); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java index f543e7d29..5d65987a6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -3,22 +3,21 @@ package com.topjohnwu.magisk; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; +import android.support.v7.widget.CardView; 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.LinearLayout; import android.widget.TextView; -import android.widget.Toast; -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 com.topjohnwu.magisk.utils.AnimationHelper; + +import org.w3c.dom.Text; -import java.io.File; import java.util.List; import butterknife.BindView; @@ -27,22 +26,39 @@ import butterknife.ButterKnife; public class ReposAdapter extends RecyclerView.Adapter { private final List mList; - private View view; + private View viewMain; private Context context; + @BindView(R.id.update) + ImageView updateImage; + @BindView(R.id.installed) + ImageView installedImage; + @BindView(R.id.popup_layout) + LinearLayout popupLayout; + @BindView(R.id.author) + TextView authorText; + @BindView(R.id.log) + TextView logText; + @BindView(R.id.updateStatus) TextView updateStatus; + @BindView(R.id.installedStatus) TextView installedStatus; + private boolean isCardExpanded; + public ReposAdapter(List list) { this.mList = list; } + private boolean mIsInstalled; + + @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false); + viewMain = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false); + ButterKnife.bind(this, viewMain); context = parent.getContext(); - - return new ViewHolder(view); + return new ViewHolder(viewMain); } @Override @@ -50,26 +66,49 @@ public class ReposAdapter extends RecyclerView.Adapter final Repo repo = mList.get(position); holder.title.setText(repo.getName()); - holder.versionName.setText(repo.getVersion()); + holder.versionName.setText(repo.getmVersion()); holder.description.setText(repo.getDescription()); - view.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - if (!prefs.contains("isInstalled_" + repo.getName())) { + Log.d("Magisk","ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (prefs.contains("repo_isInstalled_" + repo.getId())) { + mIsInstalled = prefs.getBoolean("repo_isInstalled_" + repo.getId(),false); + if (mIsInstalled) { + installedImage.setImageResource(R.drawable.ic_done_black); + installedStatus.setText(R.string.module_installed); + } + } - 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); + isCardExpanded = false; + AnimationHelper.collapse(popupLayout); + + viewMain.setOnClickListener(new View.OnClickListener() { + @Override + + public void onClick(View view) { + if (isCardExpanded) { + + AnimationHelper.collapse(popupLayout); + isCardExpanded = false; } else { - Toast.makeText(context,repo.getName() + " is already installed.",Toast.LENGTH_SHORT).show(); + AnimationHelper.expand(popupLayout); + isCardExpanded = true; + } + +// if (!mIsInstalled) { +// +// Utils.DownloadReceiver reciever = new Utils.DownloadReceiver() { +// @Override +// public void task(File file) { +// Log.d("Magisk", "Task firing"); +// new Utils.FlashZIP(context, repo.getId(), file.toString()).execute(); +// } +// }; +// String filename = repo.getId().replace(" ", "") + ".zip"; +// Utils.downloadAndReceive(context, reciever, repo.getmZipUrl(), filename); +// } else { +// Toast.makeText(context,repo.getId() + " is already installed.",Toast.LENGTH_SHORT).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 c46998f08..0e20a1294 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -17,58 +17,117 @@ public class Module { private String mName = null; private String mVersion = "(No version provided)"; private String mDescription = "(No description provided)"; - private String mUrl = null; + private String mUrl,mSupportUrl,mDonateUrl,mZipUrl,mBaseUrl,mManifestUrl,mAuthor; + private boolean mEnable, mRemove,mUpdateAvailable,mIsOnline; - private boolean mEnable; - private boolean mRemove; private String mId; private int mVersionCode; public Module(String path, Context context) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - Map keys = prefs.getAll(); - for(Map.Entry entry : keys.entrySet()){ - - if(entry.getValue().toString().contains(path)) { - Log.d("Magisk", "Hey, look a matching path, this guy's name is " + entry.getKey().replace("path_","")); - } - } mRemoveFile = path + "/remove"; mDisableFile = path + "/disable"; for (String line : Utils.readFile(path + "/module.prop")) { - String[] parts = line.split("=", 2); - if (parts.length != 2) { + String[] props = line.split("=", 2); + if (props.length != 2) { continue; } - String key = parts[0].trim(); + String key = props[0].trim(); if (key.charAt(0) == '#') { continue; } - String value = parts[1].trim(); - switch (key) { + String value = props[1].trim(); + switch (props[0]) { + case "versionCode": + this.mVersionCode = Integer.valueOf(props[1]); + break; case "name": - mName = value; + this.mName = props[1]; break; - case "version": - mVersion = value; - break; - case "description": - mDescription = value; + case "author": + this.mAuthor = props[1]; break; case "id": - mId = value; + this.mId = props[1]; break; - case "versionCode": - try { - mVersionCode = Integer.parseInt(value); - } catch (NumberFormatException e) { - mVersionCode = 0; + case "version": + this.mVersion = props[1]; + break; + case "description": + this.mDescription = props[1]; + break; + case "donate": + this.mDonateUrl = props[1]; + break; + case "support": + this.mSupportUrl = props[1]; + break; + case "donateUrl": + this.mDonateUrl = props[1]; + break; + case "zipUrl": + this.mZipUrl = props[1]; + break; + case "baseUrl": + this.mBaseUrl = props[1]; + break; + case "manifestUrl": + this.mManifestUrl = props[1]; + break; + default: + Log.d("Magisk", "Manifest string not recognized: " + props[0]); + break; + } + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (mId != null) { + Log.d("Magisk", "Module: Checking for preference named repo_" + mId); + if (prefs.contains("repo_" + mId)) { + String entryString = prefs.getString("repo_" + mId, ""); + + + String entryName = "repo" + mId; + + String[] subStrings = entryString.split("\n"); + for (String subKeys : subStrings) { + String[] idEntry = subKeys.split("=", 2); + Log.d("Magisk", "Module: Checking entry strings. Key is " + idEntry[0] + " and value is " + idEntry[1]); + if (idEntry[0].equals("id")) { + if (idEntry.length != 2) { + continue; + } + + if (idEntry[1].equals(mId)) { + Log.d("Magisk", "Module: Hey, I know I'm online..."); + mIsOnline = true; + } else mIsOnline = false; + } + if (idEntry[0].equals("versionCode")) { + if (idEntry.length != 2) { + continue; + } + + if (Integer.valueOf(idEntry[1]) > mVersionCode) { + mUpdateAvailable = true; + Log.d("Magisk", "Module: Hey, I have an update..."); + } else mUpdateAvailable = false; + } } - break; + + + } + + SharedPreferences.Editor editor = prefs.edit(); + if (mIsOnline) { + editor.putBoolean("repo_isInstalled_" + mId, true); + + } else { + editor.putBoolean("repo_isInstalled_" + mId, false); + } + editor.apply(); } } @@ -86,11 +145,11 @@ public class Module { public Module(Repo repo) { mName = repo.getName(); - mVersion = repo.getVersion(); + mVersion = repo.getmVersion(); mDescription = repo.getDescription(); mId = "foo"; mVersionCode = 111; - mUrl = repo.getZipUrl(); + mUrl = repo.getmZipUrl(); mEnable = true; mRemove = false; @@ -134,4 +193,8 @@ public class Module { return mRemove; } + public boolean isOnline() {return mIsOnline; } + + public boolean isUpdateAvailable() { return mUpdateAvailable; }; + } \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index 228e7809c..e6944915f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -15,53 +15,76 @@ import java.text.SimpleDateFormat; import java.util.Date; public class Repo { - public String name; - public String baseUrl, zipUrl, manifestUrl, logUrl, manifest, version, moduleName, moduleDescription, moduleAuthor, moduleAuthorUrl; - public Date lastUpdate; - public Boolean usesRoot, usesXposed; + private String mBaseUrl; + private String mZipUrl; + private String mLogUrl; + private String mManifestUrl; + private String mVersion; + private String mName; + private String mDescription; + private String mAuthor; + public String mAuthorUrl; + private String mId; + private String mVersionCode; + private String mSupportUrl; + private String mDonateUrl; + private Date lastUpdate; private Context appContext; - private SharedPreferences prefs; + private boolean mIsInstalled; + public Repo(String manifestString, Context context) { + ParseProps(manifestString); + appContext = context; + + } public Repo(String name, String url, Date updated, Context context) { appContext = context; - this.name = name; - this.baseUrl = url; + this.mName = name; + this.mBaseUrl = url; this.lastUpdate = updated; this.fetch(); } public Repo(String moduleName, String moduleDescription, String zipUrl, Date lastUpdated, Context context) { - Log.d("Magisk", "Hey, I'm a repo! My name is " + moduleName); appContext = context; - this.zipUrl = zipUrl; - this.moduleDescription = moduleDescription; - this.moduleName = moduleName; + this.mZipUrl = zipUrl; + this.mDescription = moduleDescription; + this.mName = moduleName; this.lastUpdate = lastUpdated; - + this.fetch(); } - public void fetch() { - prefs = PreferenceManager.getDefaultSharedPreferences(appContext); + private void fetch() { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext); + if (prefs.contains("repo_" + this.mId)) { + String repoString = prefs.getString("repo_" + this.mId,""); + if (!repoString.equals("")) { + ParseProps(repoString); + } + } + if (prefs.contains("repo_isInstalled_" + this.mId)) { + mIsInstalled = prefs.getBoolean("repo_isInstalled_" + this.mId,false); + + } + 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); - + Log.d("Magisk", "Manifest string is: " + mBaseUrl + "/contents/"); + String repoString = webreq.makeWebServiceCall(mBaseUrl + "/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"); + this.mZipUrl = jsonobject.getString("download_url"); + } else if (name.equals("module.prop")) { + this.mManifestUrl = jsonobject.getString("download_url"); + } else if (name.equals("changelog.txt")) { + this.mLogUrl = jsonobject.getString("download_url"); } } } catch (JSONException e) { @@ -69,60 +92,159 @@ public class Repo { } 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 + "\"," - + "\"lastUpdate\":\"" + lastUpdate + "\"," - + "\"logUrl\":\"" + logUrl + "\"}]"; - editor.putString("module_" + moduleName, prefsString); - editor.putBoolean("hasCachedRepos", true); - SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss"); - editor.putString("updated", sdf.toString()); - Log.d("Magisk", "Storing Preferences: " + prefsString); - editor.apply(); - - } catch (JSONException e) { - e.printStackTrace(); + WebRequest propReq = new WebRequest(); + String manifestString = propReq.makeWebServiceCall(this.mManifestUrl,WebRequest.GET,true); + if (ParseProps(manifestString)) { + PutProps(manifestString); } } - public String getName() { - return moduleName; + private void PutProps(String manifestString) { + manifestString = manifestString + "zipUrl=" + mZipUrl + "\nbaseUrl=" + mBaseUrl + "\nlogUrl=" + mLogUrl + "\nmanifestUrl=" + mManifestUrl; + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("repo_" + mId, manifestString); + editor.putBoolean("hasCachedRepos", true); + editor.putString("updated_" + mId, this.lastUpdate.toString()); + Log.d("Magisk", "Storing Preferences: " + manifestString); + editor.apply(); + } + private boolean ParseProps(String string) { + Log.d("Magisk","Repo: parseprops called for string " + string); + if ((string.length() <= 1) | (!string.contains("id"))) { + return false; + } else { + String lines[] = string.split("\\n"); + for (String line : lines) { + if (line != "") { + String props[] = line.split("="); + Log.d("Magisk", "Repo: Split values are " + props[0] + " and " + props[1]); + switch (props[0]) { + case "versionCode": + this.mVersionCode = props[1]; + break; + case "name": + this.mName = props[1]; + break; + case "author": + this.mAuthor = props[1]; + break; + case "id": + this.mId = props[1]; + break; + case "version": + this.mVersion = props[1]; + break; + case "description": + this.mDescription = props[1]; + break; + case "donate": + this.mDonateUrl = props[1]; + break; + case "support": + this.mSupportUrl = props[1]; + break; + case "donateUrl": + this.mDonateUrl = props[1]; + break; + case "zipUrl": + this.mZipUrl = props[1]; + break; + case "baseUrl": + this.mBaseUrl = props[1]; + break; + case "manifestUrl": + this.mManifestUrl = props[1]; + break; + default: + Log.d("Magisk", "Manifest string not recognized: " + props[0]); + break; + } + } + + } + return this.mName != null; + + } } - public String getVersion() { - return version; + public String getStringProperty(String mValue) { + switch (mValue) { + case "author": + return mAuthor; + case "id": + return mId; + case "version": + return mVersion; + case "description": + return mDescription; + case "supportUrl": + return mSupportUrl; + case "donateUrl": + return mDonateUrl; + case "baseeUrl": + return mBaseUrl; + case "zipUrl": + return mZipUrl; + default: + return null; + } + } + + public String getName() { + return mName; + } + + public String getmVersion() { + return mVersion; + } + + public int getmVersionCode() { + return Integer.valueOf(mVersionCode); } public String getDescription() { - return moduleDescription; + return mDescription; } - public String getZipUrl() { - return zipUrl; + public String getId() { + return mId; } - public String getLogUrl() { - return logUrl; + public String getmZipUrl() { + return mZipUrl; + } + + public String getmBaseUrl() { + return mBaseUrl; + } + + public String getmLogUrl() { + return mLogUrl; } -} \ No newline at end of file + public String getmAuthor() { + return mAuthor; + } + + public String getmDonateUrl() { + return mDonateUrl; + } + + public String getmManifestUrl() { + return mManifestUrl; + } + + public String getmSupportUrl() { + return mSupportUrl; + } + + public Date getLastUpdate() { + return lastUpdate; + } + + public boolean isInstalled() { return mIsInstalled; } +} + diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java index a18d77b13..c5e3b9c0d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java @@ -3,29 +3,39 @@ package com.topjohnwu.magisk.module; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; +import android.os.Build; import android.preference.PreferenceManager; +import android.support.annotation.NonNull; import android.util.Log; import android.widget.Toast; +import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebRequest; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.io.File; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; 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 List repos = new ArrayList() { + + }; private static final String TAG_ID = "id"; private static final String TAG_NAME = "name"; + private static String TAG = "Magisk"; private Context activityContext; private Date updatedDate, currentDate; @@ -36,39 +46,17 @@ public class RepoAdapter { new MyAsyncTask().execute(); List out = null; } else { - Log.d("Magisk", "Building from cache"); + Log.d(TAG, "Building from cache"); Map map = prefs.getAll(); repos.clear(); - for (Map.Entry entry : map.entrySet()) { - if (entry.getKey().contains("module_")) { - String repoString = entry.getValue().toString().replace(""", "\""); - JSONArray repoArray = null; - try { - repoArray = new JSONArray(repoString); - - - for (int f = 0; f < repoArray.length(); f++) { - JSONObject jsonobject = repoArray.getJSONObject(f); - String name = entry.getKey().replace("module_", ""); - name = name.replace(" ", ""); - String moduleName, moduleDescription, zipUrl; - moduleName = jsonobject.getString("moduleName"); - moduleDescription = jsonobject.getString("moduleDescription"); - zipUrl = jsonobject.getString("zipUrl"); - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - try { - updatedDate = format.parse(jsonobject.getString("lastUpdate")); - } catch (ParseException e) { - e.printStackTrace(); - } - repos.add(new Repo(name, moduleDescription, zipUrl, updatedDate, activityContext)); - - } - } catch (JSONException e) { - e.printStackTrace(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + map.entrySet().stream().filter(entry -> entry.getKey().contains("repo_")).forEach(entry -> { + String repoString = entry.getValue().toString(); + if (repoString.length() >= 0) { + repos.add(new Repo(repoString,context)); } - } + }); } } @@ -120,8 +108,8 @@ public class RepoAdapter { // TODO Auto-generated catch block e.printStackTrace(); } - - if (!name.contains("Repo.github.io")) { + if ((!name.contains("Repo.github.io"))) { + //if (!name.contains("Repo.github.io") && name.contains("template")) { repos.add(new Repo(name, url, updatedDate, activityContext)); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/AnimationHelper.java b/app/src/main/java/com/topjohnwu/magisk/utils/AnimationHelper.java new file mode 100644 index 000000000..ebb1d3301 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/AnimationHelper.java @@ -0,0 +1,58 @@ +package com.topjohnwu.magisk.utils; + +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.Transformation; +import android.widget.LinearLayout; + +public class AnimationHelper { + public static void expand(final View v) { + v.measure(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + final int targetHeight = v.getMeasuredHeight(); + + v.getLayoutParams().height = 0; + v.setVisibility(View.VISIBLE); + Animation a = new Animation() { + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + v.getLayoutParams().height = interpolatedTime == 1 + ? LinearLayout.LayoutParams.WRAP_CONTENT + : (int) (targetHeight * interpolatedTime); + v.requestLayout(); + } + + @Override + public boolean willChangeBounds() { + return true; + } + }; + + // 1dp/ms + a.setDuration((int) (targetHeight / v.getContext().getResources().getDisplayMetrics().density)); + v.startAnimation(a); + } + + public static void collapse(final View v) { + final int initialHeight = v.getMeasuredHeight(); + + Animation a = new Animation() { + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + if (interpolatedTime == 1) { + v.setVisibility(View.GONE); + } else { + v.getLayoutParams().height = initialHeight - (int) (initialHeight * interpolatedTime); + v.requestLayout(); + } + } + + @Override + public boolean willChangeBounds() { + return true; + } + }; + // 1dp/ms + a.setDuration((int) (initialHeight / v.getContext().getResources().getDisplayMetrics().density)); + v.startAnimation(a); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/GitAgent.java b/app/src/main/java/com/topjohnwu/magisk/utils/GitAgent.java new file mode 100644 index 000000000..927c4cfb1 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/GitAgent.java @@ -0,0 +1,8 @@ +package com.topjohnwu.magisk.utils; + + +public class GitAgent { + + + +} 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 ebe8a68aa..8c4322174 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -41,6 +41,7 @@ import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.List; +import java.util.Set; public class Utils { @@ -394,9 +395,8 @@ public class Utils { Log.d("Magisk", "Reload called, online mode set to " + doReload); List magiskCache = getModList(MAGISK_CACHE_PATH); RepoAdapter mr = new RepoAdapter(); - - List magiskRepos = mr.listRepos(mContext, doReload); + for (String mod : magisk) { ModulesFragment.listModules.add(new Module(mod,mContext)); } @@ -404,7 +404,9 @@ public class Utils { ModulesFragment.listModulesCache.add(new Module(mod,mContext)); } for (Repo repo : magiskRepos) { - ModulesFragment.listModulesDownload.add(repo); + if (repo.getId() != null){ + ModulesFragment.listModulesDownload.add(repo); + } } return null; diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java b/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java index 1b782a158..171ac5a8a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java @@ -18,6 +18,7 @@ public class WebRequest { static String response = null; public final static int GET = 1; public final static int POST = 2; + private boolean addNewLine; //Constructor with no parameter public WebRequest() { @@ -31,7 +32,15 @@ public class WebRequest { * @requestmethod - http request method */ public String makeWebServiceCall(String url, int requestmethod) { + addNewLine=false; return this.makeWebServiceCall(url, requestmethod, null); + + } + + public String makeWebServiceCall(String url, int requestmethod, boolean addNewLines) { + addNewLine = addNewLines; + return this.makeWebServiceCall(url, requestmethod, null); + } /** @@ -90,7 +99,7 @@ public class WebRequest { String line; BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); while ((line = br.readLine()) != null) { - response += line; + response += line + "\n"; } } else { response = ""; diff --git a/app/src/main/res/drawable/ic_done_black.xml b/app/src/main/res/drawable/ic_done_black.xml new file mode 100644 index 000000000..7affe9ba9 --- /dev/null +++ b/app/src/main/res/drawable/ic_done_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/list_item_repo.xml b/app/src/main/res/layout/list_item_repo.xml index 353a08fc9..4eea607f8 100644 --- a/app/src/main/res/layout/list_item_repo.xml +++ b/app/src/main/res/layout/list_item_repo.xml @@ -1,4 +1,8 @@ + + + + + + + + - \ No newline at end of file + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_repo_expanded.xml b/app/src/main/res/layout/list_item_repo_expanded.xml new file mode 100644 index 000000000..c7303199a --- /dev/null +++ b/app/src/main/res/layout/list_item_repo_expanded.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/single_module_fragment.xml b/app/src/main/res/layout/single_module_fragment.xml index 42363f378..e6ab2c8fc 100644 --- a/app/src/main/res/layout/single_module_fragment.xml +++ b/app/src/main/res/layout/single_module_fragment.xml @@ -1,8 +1,9 @@ - @@ -24,4 +25,4 @@ android:textStyle="italic" android:visibility="gone"/> - \ No newline at end of file + \ 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 983a104e4..6f0fe3a30 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,6 +42,9 @@ Cache modules No modules found + Update available + Module is up-to-date + Module is installed Module will be removed at next reboot Module will not be removed at next reboot Module will be disabled at next reboot From e3866eeb29eeccd6f42cd61ea49d25b3acc03c4a Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Thu, 8 Sep 2016 14:47:04 -0500 Subject: [PATCH 09/27] I think it won't break anything? --- .../topjohnwu/magisk/BaseModuleFragment.java | 120 +++++++++-- .../topjohnwu/magisk/BaseRepoFragment.java | 123 ++++++++++- .../com/topjohnwu/magisk/ModulesAdapter.java | 101 --------- .../com/topjohnwu/magisk/ModulesFragment.java | 36 +--- .../com/topjohnwu/magisk/ReposAdapter.java | 140 ------------- .../com/topjohnwu/magisk/WelcomeActivity.java | 12 +- .../com/topjohnwu/magisk/module/Module.java | 106 +++++----- .../com/topjohnwu/magisk/module/Repo.java | 60 +++--- .../topjohnwu/magisk/module/RepoAdapter.java | 135 ------------ .../topjohnwu/magisk/module/RepoHelper.java | 197 ++++++++++++++++++ .../com/topjohnwu/magisk/utils/Utils.java | 65 ++---- .../topjohnwu/magisk/utils/WebRequest.java | 11 +- .../drawable/ic_system_update_alt_black.xml | 9 + app/src/main/res/layout/list_item_repo.xml | 8 +- 14 files changed, 567 insertions(+), 556 deletions(-) delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java delete mode 100644 app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java create mode 100644 app/src/main/res/drawable/ic_system_update_alt_black.xml diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index e41a73df8..530ad3e73 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -7,13 +7,16 @@ import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; 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.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import java.util.List; @@ -23,17 +26,16 @@ import butterknife.ButterKnife; public abstract class BaseModuleFragment extends Fragment { - @BindView(R.id.recyclerView) - RecyclerView recyclerView; - @BindView(R.id.empty_rv) - TextView emptyTv; - private View view; + @BindView(R.id.recyclerView) RecyclerView recyclerView; + @BindView(R.id.empty_rv) TextView emptyTv; + + private SharedPreferences prefs; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - view = inflater.inflate(R.layout.single_module_fragment, container, false); + View view = inflater.inflate(R.layout.single_module_fragment, container, false); ButterKnife.bind(this, view); @@ -55,19 +57,16 @@ public abstract class BaseModuleFragment extends Fragment { return view; } - recyclerView.setAdapter(new ModulesAdapter(listModules(), new Utils.ItemClickListener() { - @Override - public void onItemClick(View chk, int position) { - // On Checkbox change listener - CheckBox chbox = (CheckBox) chk; + recyclerView.setAdapter(new ModulesAdapter(listModules(), (chk, position) -> { + // On Checkbox change listener + CheckBox chbox = (CheckBox) chk; - if (!chbox.isChecked()) { - BaseModuleFragment.this.listModules().get(position).createDisableFile(); - Snackbar.make(chk, R.string.disable_file_created, Snackbar.LENGTH_SHORT).show(); - } else { - BaseModuleFragment.this.listModules().get(position).removeDisableFile(); - Snackbar.make(chk, 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(); } }, (deleteBtn, position) -> { // On delete button click listener @@ -85,4 +84,89 @@ public abstract class BaseModuleFragment extends Fragment { protected abstract List listModules(); + + public class ModulesAdapter extends RecyclerView.Adapter { + + private final List mList; + private final Utils.ItemClickListener chboxListener; + private final Utils.ItemClickListener deleteBtnListener; + private final Utils.ItemClickListener unDeleteBtnListener; + + public ModulesAdapter(List list, Utils.ItemClickListener chboxListener, Utils.ItemClickListener deleteBtnListener, Utils.ItemClickListener undeleteBtnListener) { + this.mList = list; + this.chboxListener = chboxListener; + this.deleteBtnListener = deleteBtnListener; + this.unDeleteBtnListener = undeleteBtnListener; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_module, parent, false); + + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(final ViewHolder holder, int position) { + final Module module = mList.get(position); + Log.d("Magisk","ModulesAdapter: Trying set up bindview from list pos " + position + " and " + module.getName() ); + + holder.title.setText(module.getName()); + holder.versionName.setText(module.getVersion()); + holder.description.setText(module.getDescription()); + + holder.checkBox.setChecked(module.isEnabled()); + holder.checkBox.setOnCheckedChangeListener((compoundButton, b) -> chboxListener.onItemClick(compoundButton, holder.getAdapterPosition())); + + 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); + } + + private void updateDeleteButton(ViewHolder holder, Module module) { + holder.warning.setVisibility(module.willBeRemoved() ? View.VISIBLE : View.GONE); + + if (module.willBeRemoved()) { + holder.delete.setImageResource(R.drawable.ic_undelete); + } else { + holder.delete.setImageResource(R.drawable.ic_delete); + } + } + + @Override + public int getItemCount() { + return mList.size(); + } + + class ViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.title) TextView title; + + @BindView(R.id.version_name) TextView versionName; + @BindView(R.id.description) TextView description; + + @BindView(R.id.warning) TextView warning; + + @BindView(R.id.checkbox) CheckBox checkBox; + @BindView(R.id.delete) + ImageView delete; + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + if (!Shell.rootAccess()) { + checkBox.setEnabled(false); + delete.setEnabled(false); + } + } + } + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java index bc7d49474..082e14878 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java @@ -1,17 +1,26 @@ package com.topjohnwu.magisk; +import android.content.Context; +import android.content.SharedPreferences; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; -import android.support.v7.widget.CardView; 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.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import com.topjohnwu.magisk.module.Repo; +import com.topjohnwu.magisk.utils.AnimationHelper; +import com.topjohnwu.magisk.utils.Utils; +import java.io.File; import java.util.List; import butterknife.BindView; @@ -26,6 +35,7 @@ public abstract class BaseRepoFragment extends Fragment { + @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -40,7 +50,7 @@ public abstract class BaseRepoFragment extends Fragment { return view; } - + Log.d("Magisk","BaseRepoFragment: ListRepos size is " + listRepos().size()); recyclerView.setAdapter(new ReposAdapter(listRepos()) { }); @@ -49,4 +59,113 @@ public abstract class BaseRepoFragment extends Fragment { protected abstract List listRepos(); + + public class ReposAdapter extends RecyclerView.Adapter { + + private final List mList; + private View viewMain; + private Context context; + @BindView(R.id.update) + ImageView updateImage; + @BindView(R.id.installed) + ImageView installedImage; +// @BindView(R.id.popup_layout) +// LinearLayout popupLayout; + + + private boolean isCardExpanded; + private boolean mIsInstalled, mCanUpdate; + + public ReposAdapter(List list) { + this.mList = list; + + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + viewMain = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false); + ButterKnife.bind(this, viewMain); + context = parent.getContext(); + return new ViewHolder(viewMain); + } + + @Override + public void onBindViewHolder(final ViewHolder holder, int position) { + final Repo repo = mList.get(position); + Log.d("Magisk","ReposAdapter: Trying set up bindview from list pos " + position + " out of a total of " + mList.size() + " and " + repo.getId() ); + if (repo.getId() != null) { + holder.title.setText(repo.getName()); + holder.versionName.setText(repo.getmVersion()); + holder.description.setText(repo.getDescription()); + Log.d("Magisk", "ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (prefs.contains("repo-isInstalled_" + repo.getId())) { + mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); + if (mIsInstalled) { + installedImage.setImageResource(R.drawable.ic_done_black); + } + mCanUpdate = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); + if (mCanUpdate) { + updateImage.setImageResource(R.drawable.ic_system_update_alt_black); + } + } + + isCardExpanded = false; +// AnimationHelper.collapse(popupLayout); + + viewMain.setOnClickListener(new View.OnClickListener() { + @Override + + public void onClick(View view) { + if (isCardExpanded) { +// AnimationHelper.expand(popupLayout); + isCardExpanded = false; + } else { +// AnimationHelper.collapse(popupLayout); + isCardExpanded = true; + + } + +// if (!mIsInstalled | mCanUpdate) { +// +// Utils.DownloadReceiver reciever = new Utils.DownloadReceiver() { +// @Override +// public void task(File file) { +// Log.d("Magisk", "Task firing"); +// new Utils.FlashZIP(context, repo.getId(), file.toString()).execute(); +// } +// }; +// String filename = repo.getId().replace(" ", "") + ".zip"; +// Utils.downloadAndReceive(context, reciever, repo.getmZipUrl(), filename); +// } else { +// Toast.makeText(context,repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); +// } + } + }); + } + + + } + + + + + @Override + public int getItemCount() { + return mList.size(); + } + + 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); + } + } + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java deleted file mode 100644 index c5b015f4c..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesAdapter.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.topjohnwu.magisk; - -import android.support.v7.widget.RecyclerView; -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.utils.Shell; -import com.topjohnwu.magisk.utils.Utils; - -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class ModulesAdapter extends RecyclerView.Adapter { - - private final List mList; - private final Utils.ItemClickListener chboxListener; - private final Utils.ItemClickListener deleteBtnListener; - private final Utils.ItemClickListener unDeleteBtnListener; - - public ModulesAdapter(List list, Utils.ItemClickListener chboxListener, Utils.ItemClickListener deleteBtnListener, Utils.ItemClickListener undeleteBtnListener) { - this.mList = list; - this.chboxListener = chboxListener; - this.deleteBtnListener = deleteBtnListener; - this.unDeleteBtnListener = undeleteBtnListener; - } - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_module, parent, false); - - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(final ViewHolder holder, int position) { - final Module module = mList.get(position); - - holder.title.setText(module.getName()); - holder.versionName.setText(module.getVersion()); - holder.description.setText(module.getDescription()); - - holder.checkBox.setChecked(module.isEnabled()); - holder.checkBox.setOnCheckedChangeListener((compoundButton, b) -> chboxListener.onItemClick(compoundButton, holder.getAdapterPosition())); - - 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); - } - - private void updateDeleteButton(ViewHolder holder, Module module) { - holder.warning.setVisibility(module.willBeRemoved() ? View.VISIBLE : View.GONE); - - if (module.willBeRemoved()) { - holder.delete.setImageResource(R.drawable.ic_undelete); - } else { - holder.delete.setImageResource(R.drawable.ic_delete); - } - } - - @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; - - @BindView(R.id.warning) TextView warning; - - @BindView(R.id.checkbox) CheckBox checkBox; - @BindView(R.id.delete) ImageView delete; - - public ViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - if (!Shell.rootAccess()) { - checkBox.setEnabled(false); - delete.setEnabled(false); - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 0af544180..6a2cc8ea0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -56,23 +56,13 @@ public class ModulesFragment extends Fragment { View view = inflater.inflate(R.layout.modules_fragment, container, false); ButterKnife.bind(this, view); + //new Utils.LoadModules(getActivity(),false).execute(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); - if (prefs.contains("hasCachedRepos")) { - new Utils.LoadModules(getActivity(), false).execute(); - } else { - new Utils.LoadModules(getActivity(), true).execute(); - } - new updateUI().execute(); setHasOptionsMenu(true); return view; } - public void updateThisShit() { - new Utils.LoadModules(getActivity(), true).execute(); - new updateUI().execute(); - setHasOptionsMenu(true); - } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { @@ -93,8 +83,6 @@ public class ModulesFragment extends Fragment { } - - public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case FILE_SELECT_CODE: @@ -117,8 +105,7 @@ public class ModulesFragment extends Fragment { listModulesCache.clear(); listModulesDownload.clear(); progressBar.setVisibility(View.VISIBLE); - ta = new TabsAdapter(getChildFragmentManager()); - viewPager.setAdapter(ta); + viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); new Utils.LoadModules(getActivity(),true).execute(); new updateUI().execute(); @@ -128,19 +115,6 @@ public class ModulesFragment extends Fragment { return super.onOptionsItemSelected(item); } - public void redrawLayout() { - listModules.clear(); - listModulesCache.clear(); - listModulesDownload.clear(); - progressBar.setVisibility(View.VISIBLE); - ta = new TabsAdapter(getChildFragmentManager()); - viewPager.setAdapter(ta); - tabLayout.setupWithViewPager(viewPager); - new Utils.LoadModules(getActivity(),false).execute(); - new updateUI().execute(); - - } - public static class NormalModuleFragment extends BaseModuleFragment { @Override @@ -168,7 +142,7 @@ public class ModulesFragment extends Fragment { } - public class updateUI extends AsyncTask { + private class updateUI extends AsyncTask { @Override protected Void doInBackground(Void... voids) { @@ -180,8 +154,8 @@ public class ModulesFragment extends Fragment { super.onPostExecute(v); progressBar.setVisibility(View.GONE); - ta = new TabsAdapter(getChildFragmentManager()); - viewPager.setAdapter(ta); + + viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java deleted file mode 100644 index 5d65987a6..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.topjohnwu.magisk; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.support.v7.widget.CardView; -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.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.topjohnwu.magisk.module.Repo; -import com.topjohnwu.magisk.utils.AnimationHelper; - -import org.w3c.dom.Text; - -import java.util.List; - -import butterknife.BindView; -import butterknife.ButterKnife; - -public class ReposAdapter extends RecyclerView.Adapter { - - private final List mList; - private View viewMain; - private Context context; - @BindView(R.id.update) - ImageView updateImage; - @BindView(R.id.installed) - ImageView installedImage; - @BindView(R.id.popup_layout) - LinearLayout popupLayout; - @BindView(R.id.author) - TextView authorText; - @BindView(R.id.log) - TextView logText; - @BindView(R.id.updateStatus) TextView updateStatus; - @BindView(R.id.installedStatus) TextView installedStatus; - private boolean isCardExpanded; - - - public ReposAdapter(List list) { - this.mList = list; - - } - - private boolean mIsInstalled; - - - - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - viewMain = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false); - ButterKnife.bind(this, viewMain); - context = parent.getContext(); - return new ViewHolder(viewMain); - } - - @Override - public void onBindViewHolder(final ViewHolder holder, int position) { - final Repo repo = mList.get(position); - - holder.title.setText(repo.getName()); - holder.versionName.setText(repo.getmVersion()); - holder.description.setText(repo.getDescription()); - Log.d("Magisk","ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - if (prefs.contains("repo_isInstalled_" + repo.getId())) { - mIsInstalled = prefs.getBoolean("repo_isInstalled_" + repo.getId(),false); - if (mIsInstalled) { - installedImage.setImageResource(R.drawable.ic_done_black); - installedStatus.setText(R.string.module_installed); - } - } - - isCardExpanded = false; - AnimationHelper.collapse(popupLayout); - - viewMain.setOnClickListener(new View.OnClickListener() { - @Override - - public void onClick(View view) { - if (isCardExpanded) { - - AnimationHelper.collapse(popupLayout); - isCardExpanded = false; - } else { - AnimationHelper.expand(popupLayout); - isCardExpanded = true; - - } - -// if (!mIsInstalled) { -// -// Utils.DownloadReceiver reciever = new Utils.DownloadReceiver() { -// @Override -// public void task(File file) { -// Log.d("Magisk", "Task firing"); -// new Utils.FlashZIP(context, repo.getId(), file.toString()).execute(); -// } -// }; -// String filename = repo.getId().replace(" ", "") + ".zip"; -// Utils.downloadAndReceive(context, reciever, repo.getmZipUrl(), filename); -// } else { -// Toast.makeText(context,repo.getId() + " is already installed.",Toast.LENGTH_SHORT).show(); -// } - } - }); - - - } - - - - - @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/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java index 6d34d7cfd..cb3c30bde 100644 --- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java @@ -4,10 +4,12 @@ import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.preference.PreferenceManager; import android.support.annotation.IdRes; import android.support.annotation.NonNull; import android.support.design.widget.NavigationView; @@ -58,7 +60,15 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView } new Utils.Initialize(this).execute(); new Utils.CheckUpdates(this).execute(); - new Utils.LoadModules(getApplication(),false).execute(); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + if (!prefs.contains("oauth_key")) { + + } + if (!prefs.contains("hasCachedRepos")) { + new Utils.LoadModules(this, true).execute(); + } else { + new Utils.LoadModules(getApplication(),false).execute(); + } setSupportActionBar(toolbar); 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 0e20a1294..f5ab7f1e9 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -45,90 +45,98 @@ public class Module { this.mVersionCode = Integer.valueOf(props[1]); break; case "name": - this.mName = props[1]; + this.mName = value; break; case "author": - this.mAuthor = props[1]; + this.mAuthor = value; break; case "id": - this.mId = props[1]; + this.mId = value; break; case "version": - this.mVersion = props[1]; + this.mVersion = value; break; case "description": - this.mDescription = props[1]; + this.mDescription = value; break; case "donate": - this.mDonateUrl = props[1]; + this.mDonateUrl = value; break; case "support": - this.mSupportUrl = props[1]; + this.mSupportUrl = value; break; case "donateUrl": - this.mDonateUrl = props[1]; + this.mDonateUrl = value; break; case "zipUrl": - this.mZipUrl = props[1]; + this.mZipUrl = value; break; case "baseUrl": - this.mBaseUrl = props[1]; + this.mBaseUrl = value; break; case "manifestUrl": - this.mManifestUrl = props[1]; + this.mManifestUrl = value; break; default: - Log.d("Magisk", "Manifest string not recognized: " + props[0]); + Log.d("Magisk", "Module: Manifest string not recognized: " + props[0]); break; } - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - if (mId != null) { - Log.d("Magisk", "Module: Checking for preference named repo_" + mId); - if (prefs.contains("repo_" + mId)) { - String entryString = prefs.getString("repo_" + mId, ""); + } - String entryName = "repo" + mId; + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - String[] subStrings = entryString.split("\n"); - for (String subKeys : subStrings) { - String[] idEntry = subKeys.split("=", 2); - Log.d("Magisk", "Module: Checking entry strings. Key is " + idEntry[0] + " and value is " + idEntry[1]); - if (idEntry[0].equals("id")) { - if (idEntry.length != 2) { - continue; - } + if (this.mId != null && !this.mId.isEmpty()) { + String preferenceString = "repo_" + this.mId; + String preferenceKey = prefs.getString(preferenceString,"nope"); + Log.d("Magisk", "Module: Checking for preference named " + preferenceString); + if (!preferenceKey.equals("nope")) { + Log.d("Magisk", "Module: repo_" + mId + " found."); + String entryString = prefs.getString("repo_" + mId, ""); - if (idEntry[1].equals(mId)) { - Log.d("Magisk", "Module: Hey, I know I'm online..."); - mIsOnline = true; - } else mIsOnline = false; + String[] subStrings = entryString.split("\n"); + for (String subKeys : subStrings) { + String[] idEntry = subKeys.split("=", 2); + if (idEntry[0].equals("id")) { + if (idEntry.length != 2) { + continue; } - if (idEntry[0].equals("versionCode")) { - if (idEntry.length != 2) { - continue; - } - if (Integer.valueOf(idEntry[1]) > mVersionCode) { - mUpdateAvailable = true; - Log.d("Magisk", "Module: Hey, I have an update..."); - } else mUpdateAvailable = false; - } + if (idEntry[1].equals(mId)) { + Log.d("Magisk", "Module: Hey, I know I'm online..."); + mIsOnline = true; + } else mIsOnline = false; } + if (idEntry[0].equals("versionCode")) { + if (idEntry.length != 2) { + continue; + } - + if (Integer.valueOf(idEntry[1]) > mVersionCode) { + mUpdateAvailable = true; + Log.d("Magisk", "Module: Hey, I have an update..."); + } else mUpdateAvailable = false; + } } - SharedPreferences.Editor editor = prefs.edit(); - if (mIsOnline) { - editor.putBoolean("repo_isInstalled_" + mId, true); - } else { - editor.putBoolean("repo_isInstalled_" + mId, false); - } - editor.apply(); } + + SharedPreferences.Editor editor = prefs.edit(); + if (mIsOnline) { + editor.putBoolean("repo-isInstalled_" + mId, true); + + } else { + editor.putBoolean("repo-isInstalled_" + mId, false); + } + + if (mUpdateAvailable) { + editor.putBoolean("repo-canUpdate_" + mId, true); + } else { + editor.putBoolean("repo-canUpdate_" + mId, false); + } + editor.apply(); } if (mName == null) { @@ -147,8 +155,8 @@ public class Module { mName = repo.getName(); mVersion = repo.getmVersion(); mDescription = repo.getDescription(); - mId = "foo"; - mVersionCode = 111; + mId = repo.getId(); + mVersionCode = repo.getmVersionCode(); mUrl = repo.getmZipUrl(); mEnable = true; mRemove = false; diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index e6944915f..5814ab04c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -28,21 +28,23 @@ public class Repo { private String mVersionCode; private String mSupportUrl; private String mDonateUrl; - private Date lastUpdate; + private String lastUpdate; private Context appContext; - private boolean mIsInstalled; + private boolean mIsInstalled,mCanUpdate; public Repo(String manifestString, Context context) { - ParseProps(manifestString); appContext = context; + ParseProps(manifestString); } + + public Repo(String name, String url, Date updated, Context context) { appContext = context; this.mName = name; this.mBaseUrl = url; - this.lastUpdate = updated; + this.lastUpdate = updated.toString(); this.fetch(); } @@ -52,28 +54,16 @@ public class Repo { this.mZipUrl = zipUrl; this.mDescription = moduleDescription; this.mName = moduleName; - this.lastUpdate = lastUpdated; + this.lastUpdate = lastUpdated.toString(); this.fetch(); } - private void fetch() { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext); - if (prefs.contains("repo_" + this.mId)) { - String repoString = prefs.getString("repo_" + this.mId,""); - if (!repoString.equals("")) { - ParseProps(repoString); - } - } - if (prefs.contains("repo_isInstalled_" + this.mId)) { - mIsInstalled = prefs.getBoolean("repo_isInstalled_" + this.mId,false); - - } - + public void fetch() { WebRequest webreq = new WebRequest(); // Construct initial url for contents - Log.d("Magisk", "Manifest string is: " + mBaseUrl + "/contents/"); - String repoString = webreq.makeWebServiceCall(mBaseUrl + "/contents/", WebRequest.GET); + Log.d("Magisk", "Repo: Fetch called, Manifest string is: " + mBaseUrl + "/contents?access_token=5c9f47a299d48a6a649af3587bc97200bafcac65"); + String repoString = webreq.makeWebServiceCall(mBaseUrl + "/contents?access_token=5c9f47a299d48a6a649af3587bc97200bafcac65", WebRequest.GET); try { JSONArray repoArray = new JSONArray(repoString); for (int f = 0; f < repoArray.length(); f++) { @@ -91,9 +81,11 @@ public class Repo { e.printStackTrace(); } - Log.d("Magisk", "Inner fetch: " + repoString); + Log.d("Magisk", "Repo: Inner fetch: " + mManifestUrl + "?access_token=5c9f47a299d48a6a649af3587bc97200bafcac65"); WebRequest propReq = new WebRequest(); - String manifestString = propReq.makeWebServiceCall(this.mManifestUrl,WebRequest.GET,true); + String manifestString = propReq.makeWebServiceCall(mManifestUrl,WebRequest.GET,true); + Log.d("Magisk","Repo: parseprops called from fetch for string " + manifestString); + if (ParseProps(manifestString)) { PutProps(manifestString); } @@ -111,7 +103,7 @@ public class Repo { editor.apply(); } private boolean ParseProps(String string) { - Log.d("Magisk","Repo: parseprops called for string " + string); + if ((string.length() <= 1) | (!string.contains("id"))) { return false; } else { @@ -119,7 +111,6 @@ public class Repo { for (String line : lines) { if (line != "") { String props[] = line.split("="); - Log.d("Magisk", "Repo: Split values are " + props[0] + " and " + props[1]); switch (props[0]) { case "versionCode": this.mVersionCode = props[1]; @@ -157,6 +148,9 @@ public class Repo { case "manifestUrl": this.mManifestUrl = props[1]; break; + case "logUrl": + this.mLogUrl = props[1]; + break; default: Log.d("Magisk", "Manifest string not recognized: " + props[0]); break; @@ -164,7 +158,20 @@ public class Repo { } } - return this.mName != null; + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext); + if (prefs.contains("repo-isInstalled_" + this.mId)) { + mIsInstalled = prefs.getBoolean("repo-isInstalled_" + this.mId,false); + } + if (prefs.contains("repo-canUpdate_" + this.mId)) { + mCanUpdate = prefs.getBoolean("repo-canUpdate_" + this.mId,false); + } + if (prefs.contains("updated_" + this.mId)) { + lastUpdate = prefs.getString("updated_" + this.mId,""); + } + + + + return this.mId != null; } } @@ -241,10 +248,11 @@ public class Repo { return mSupportUrl; } - public Date getLastUpdate() { + public String getLastUpdate() { return lastUpdate; } public boolean isInstalled() { return mIsInstalled; } + public boolean canUpdate() { return mCanUpdate; } } diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java deleted file mode 100644 index c5e3b9c0d..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoAdapter.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.topjohnwu.magisk.module; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.AsyncTask; -import android.os.Build; -import android.preference.PreferenceManager; -import android.support.annotation.NonNull; -import android.util.Log; -import android.widget.Toast; - -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.utils.WebRequest; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -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 static String TAG = "Magisk"; - private Context activityContext; - private Date updatedDate, currentDate; - - public List listRepos(Context context, boolean refresh) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - if (!prefs.contains("hasCachedRepos") | refresh) { - activityContext = context; - new MyAsyncTask().execute(); - List out = null; - } else { - Log.d(TAG, "Building from cache"); - Map map = prefs.getAll(); - repos.clear(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - map.entrySet().stream().filter(entry -> entry.getKey().contains("repo_")).forEach(entry -> { - String repoString = entry.getValue().toString(); - if (repoString.length() >= 0) { - repos.add(new Repo(repoString,context)); - } - - }); - } - - } - - - return repos; - } - - - class MyAsyncTask extends AsyncTask { - - @Override - protected void onPreExecute() { - super.onPreExecute(); - - } - - @Override - protected void onProgressUpdate(String... values) { - super.onProgressUpdate(values); - Toast.makeText(activityContext, "Refreshing online modules", Toast.LENGTH_SHORT).show(); - - } - - @Override - protected Void doInBackground(String... params) { - publishProgress(); - // 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("Magisk", "doInBackground Running, String: " + jsonStr + " Url: " + url); - - - 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"); - String lastUpdate = jsonobject.getString("updated_at"); - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - try { - updatedDate = format.parse(lastUpdate); - - } catch (ParseException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if ((!name.contains("Repo.github.io"))) { - //if (!name.contains("Repo.github.io") && name.contains("template")) { - repos.add(new Repo(name, url, updatedDate, activityContext)); - } - } - } 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/module/RepoHelper.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java new file mode 100644 index 000000000..d3fdfc0e9 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java @@ -0,0 +1,197 @@ +package com.topjohnwu.magisk.module; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Build; +import android.preference.PreferenceManager; +import android.util.Log; +import android.widget.Toast; + +import com.topjohnwu.magisk.utils.WebRequest; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +public class RepoHelper { + private String[] result; + private static String url = "https://api.github.com/orgs/Magisk-Modules-Repo/repos?access_token=5c9f47a299d48a6a649af3587bc97200bafcac65"; + private static List repos = new ArrayList(); + private static final String TAG_ID = "id"; + private static final String TAG_NAME = "name"; + private static String TAG = "Magisk"; + private String mName,mId,mUrl; + private Context activityContext; + private Date updatedDate, currentDate; + private SharedPreferences prefs; + private boolean apiFail; + + public List listRepos(Context context, boolean refresh) { + prefs = PreferenceManager.getDefaultSharedPreferences(context); + activityContext = context; + if (!prefs.contains("hasCachedRepos") | refresh) { + Log.d(TAG, "RepoHelper: Building from web"); + new MyAsyncTask().execute(); + List out = null; + } else { + Log.d(TAG, "RepoHelper: Building from cache"); + repos.clear(); + Map map = prefs.getAll(); + for(Map.Entry entry : map.entrySet()){ + if (entry.getKey().contains("repo_")) { + Log.d("Magisk","RepoHelper: found entry for repo " + entry.getKey()); + String repoString = entry.getValue().toString().replace(""", "\""); + String[] repoStrings = repoString.split("\n"); + for(String string : repoStrings) { + String[] splitStrings = string.split("="); + switch(splitStrings[0]) { + case ("id"): + mId = splitStrings[1]; + break; + case ("baseUrl"): + mUrl = splitStrings[1]; + break; + default: + break; + } + + } + Log.d("Magisk","RepoHelper: adding repo with id of " + mId); + repos.add(new Repo(repoString,activityContext)); + + + } + + } + + + + } + + + return repos; + } + + + class MyAsyncTask extends AsyncTask { + + @Override + protected void onPreExecute() { + super.onPreExecute(); + + } + + @Override + protected void onProgressUpdate(String... values) { + super.onProgressUpdate(values); + Toast.makeText(activityContext, "Refreshing online modules", Toast.LENGTH_SHORT).show(); + + } + + @Override + protected Void doInBackground(String... params) { + publishProgress(); + // 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("Magisk", "doInBackground Running, String: " + jsonStr + " Url: " + url); + if(jsonStr != null && !jsonStr.isEmpty()) { + + 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"); + String lastUpdate = jsonobject.getString("updated_at"); + String mId = ""; + String cacheUpdate = ""; + String manifestString = ""; + boolean doUpdate = true; + boolean hasCachedDate = false; + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + Map map = prefs.getAll(); + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().toString().contains(url)) { + Log.d("Magisk", "RepoHelper: found matching URL"); + manifestString = entry.getValue().toString(); + String[] entryStrings = entry.getValue().toString().split("\n"); + for (String valueString : entryStrings) { + String[] valueSub = valueString.split("="); + if (valueSub[0].equals("id")) { + mId = valueSub[1]; + Log.d("Magisk", "RepoHelper: Got id for package of " + mId); + if (prefs.contains("updated_" + mId)) { + cacheUpdate = prefs.getString("updated_" + mId, ""); + hasCachedDate = true; + } + } + } + + } + } + try { + updatedDate = format.parse(lastUpdate); + Log.d("Magisk", "RepoHelper: Dates found, online is " + updatedDate + " and cached is " + cacheUpdate); + + if (hasCachedDate) { + + doUpdate = !cacheUpdate.equals(updatedDate.toString()); + Log.d("Magisk", "RepoHelper: DoUpdate is " + doUpdate); + } + + + } catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (!name.contains("Repo.github.io")) { + if (doUpdate) { + repos.add(new Repo(name, url, updatedDate, activityContext)); + Log.d(TAG, "RepoHelper: Trying to add new repo for online refresh - " + name); + } else { + repos.add(new Repo(manifestString, activityContext)); + Log.d(TAG, "RepoHelper: Trying to add new repo using manifestString of " + mId); + } + } + for (int f = 0; f < repos.size(); f++) { + repos.get(f).fetch(); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + apiFail = false; + } else { + apiFail = true; + } + return null; + + + } + + protected void onPostExecute(Void v) { + if (apiFail) { + Toast.makeText(activityContext,"GitHub API Limit reached, please try refreshing again in an hour.",Toast.LENGTH_LONG).show(); + } + + } // 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 8c4322174..c4fdfb4f5 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -25,7 +25,7 @@ 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.RepoAdapter; +import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.module.Repo; import org.json.JSONArray; @@ -38,16 +38,14 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.List; -import java.util.Set; public class Utils { public static int magiskVersion, remoteMagiskVersion = -1, remoteAppVersion = -1; public static String magiskLink, magiskChangelog, appChangelog, appLink, phhLink, supersuLink; private Context appContext; + private static final String TAG = "Magisk"; public static final String MAGISK_PATH = "/magisk"; public static final String MAGISK_CACHE_PATH = "/cache/magisk"; @@ -373,17 +371,25 @@ public class Utils { } } + public static class AuthGithub extends AsyncTask { + private static String mClientToken = "5c9f47a299d48a6a649af3587bc97200bafcac65"; + + public AuthGithub(Context context) {} + + @Override + protected Void doInBackground(Void... voids) { + return null; + } + } + public static class LoadModules extends AsyncTask { private Context mContext; private boolean doReload; public LoadModules(Context context, boolean reload) { - Log.d("Magisk", "LoadModules created, online is " + reload); mContext = context; doReload = reload; - - } @Override @@ -392,30 +398,26 @@ public class Utils { ModulesFragment.listModulesCache.clear(); ModulesFragment.listModulesDownload.clear(); List magisk = getModList(MAGISK_PATH); - Log.d("Magisk", "Reload called, online mode set to " + doReload); + Log.d("Magisk", "Utils: Reload called, loading modules from" + (doReload ? " the internet " : " cache")); List magiskCache = getModList(MAGISK_CACHE_PATH); - RepoAdapter mr = new RepoAdapter(); + RepoHelper mr = new RepoHelper(); List magiskRepos = mr.listRepos(mContext, doReload); for (String mod : magisk) { + Log.d("Magisk","Utils: Adding module from string " + mod); ModulesFragment.listModules.add(new Module(mod,mContext)); } for (String mod : magiskCache) { + Log.d("Magisk","Utils: Adding cache module from string " + mod); ModulesFragment.listModulesCache.add(new Module(mod,mContext)); } for (Repo repo : magiskRepos) { - if (repo.getId() != null){ - ModulesFragment.listModulesDownload.add(repo); - } + Log.d("Magisk","Utils: Adding repo from string " + repo.getId()); + ModulesFragment.listModulesDownload.add(repo); } return null; } - - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - } } public static class FlashZIP extends AsyncTask { @@ -462,35 +464,6 @@ public class Utils { if (!result) { Toast.makeText(mContext, mContext.getString(R.string.manual_install, mPath), Toast.LENGTH_LONG).show(); return; - } else { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); - String jsonString = prefs.getString("module_" + mName,""); - String retSplit[] = ret.toString().split("Using path:"); - String ret2Split[] = retSplit[1].split(","); - String ret3Split[] = ret2Split[0].split("/"); - String finalSplit = "/" + ret3Split[1] + "/" + ret3Split[2]; - Log.d("Magisk","Damn, all that work for one path " + finalSplit); - if (!jsonString.equals("")) { - - JSONArray repoArray = null; - try { - repoArray = new JSONArray(jsonString); - - - for (int f = 0; f < repoArray.length(); f++) { - JSONObject jsonobject = repoArray.getJSONObject(f); - String name = mName; - Boolean installed = true; - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean("isInstalled_" + mName,true); - editor.putString("path_" + mName,finalSplit); - editor.apply(); - - } - } catch (JSONException e) { - e.printStackTrace(); - } - } } done(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java b/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java index 171ac5a8a..d01649e97 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/WebRequest.java @@ -1,5 +1,7 @@ package com.topjohnwu.magisk.utils; +import android.util.Log; + import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; @@ -33,12 +35,15 @@ public class WebRequest { */ public String makeWebServiceCall(String url, int requestmethod) { addNewLine=false; + Log.d("Magisk","WebRequest: Service call received for URL " + url); return this.makeWebServiceCall(url, requestmethod, null); + } public String makeWebServiceCall(String url, int requestmethod, boolean addNewLines) { addNewLine = addNewLines; + Log.d("Magisk","WebRequest: Service call(bool) received for URL " + url); return this.makeWebServiceCall(url, requestmethod, null); } @@ -99,7 +104,11 @@ public class WebRequest { String line; BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); while ((line = br.readLine()) != null) { - response += line + "\n"; + if (addNewLine) { + response += line + "\n"; + } else { + response += line; + } } } else { response = ""; diff --git a/app/src/main/res/drawable/ic_system_update_alt_black.xml b/app/src/main/res/drawable/ic_system_update_alt_black.xml new file mode 100644 index 000000000..25b07b5b4 --- /dev/null +++ b/app/src/main/res/drawable/ic_system_update_alt_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/list_item_repo.xml b/app/src/main/res/layout/list_item_repo.xml index 4eea607f8..71f9d461e 100644 --- a/app/src/main/res/layout/list_item_repo.xml +++ b/app/src/main/res/layout/list_item_repo.xml @@ -1,8 +1,5 @@ - + - + - \ No newline at end of file From 214649ec20b67285ee40b265d86e9190f6101f43 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Thu, 8 Sep 2016 15:47:10 -0500 Subject: [PATCH 10/27] Apparently Github is sensitive... --- .../com/topjohnwu/magisk/module/Repo.java | 19 +++++-- .../topjohnwu/magisk/module/RepoHelper.java | 8 +-- .../com/topjohnwu/magisk/utils/Utils.java | 50 ++++++++++++++++--- app/src/main/res/values/strings.xml | 2 + 4 files changed, 66 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index 5814ab04c..d02cedc8e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -5,13 +5,14 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.util.Log; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebRequest; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.text.SimpleDateFormat; import java.util.Date; public class Repo { @@ -32,6 +33,7 @@ public class Repo { private Context appContext; private boolean mIsInstalled,mCanUpdate; + public Repo(String manifestString, Context context) { appContext = context; ParseProps(manifestString); @@ -45,6 +47,7 @@ public class Repo { this.mName = name; this.mBaseUrl = url; this.lastUpdate = updated.toString(); + this.fetch(); } @@ -60,10 +63,11 @@ public class Repo { } public void fetch() { + WebRequest webreq = new WebRequest(); // Construct initial url for contents - Log.d("Magisk", "Repo: Fetch called, Manifest string is: " + mBaseUrl + "/contents?access_token=5c9f47a299d48a6a649af3587bc97200bafcac65"); - String repoString = webreq.makeWebServiceCall(mBaseUrl + "/contents?access_token=5c9f47a299d48a6a649af3587bc97200bafcac65", WebRequest.GET); + Log.d("Magisk", "Repo: Fetch called, Manifest string is: " + mBaseUrl + "/contents?access_token=" + Utils.procFile(appContext.getString(R.string.some_string),appContext)); + String repoString = webreq.makeWebServiceCall(mBaseUrl + "/contents?access_token=" + Utils.procFile(appContext.getString(R.string.some_string),appContext), WebRequest.GET); try { JSONArray repoArray = new JSONArray(repoString); for (int f = 0; f < repoArray.length(); f++) { @@ -81,7 +85,7 @@ public class Repo { e.printStackTrace(); } - Log.d("Magisk", "Repo: Inner fetch: " + mManifestUrl + "?access_token=5c9f47a299d48a6a649af3587bc97200bafcac65"); + Log.d("Magisk", "Repo: Inner fetch: " + mManifestUrl + "?access_token=" + Utils.procFile(appContext.getString(R.string.some_string),appContext)); WebRequest propReq = new WebRequest(); String manifestString = propReq.makeWebServiceCall(mManifestUrl,WebRequest.GET,true); Log.d("Magisk","Repo: parseprops called from fetch for string " + manifestString); @@ -176,6 +180,13 @@ public class Repo { } } + + + + + + + public String getStringProperty(String mValue) { switch (mValue) { case "author": diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java index d3fdfc0e9..40db33fe8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java @@ -3,11 +3,12 @@ package com.topjohnwu.magisk.module; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; -import android.os.Build; import android.preference.PreferenceManager; import android.util.Log; import android.widget.Toast; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebRequest; import org.json.JSONArray; @@ -23,7 +24,7 @@ import java.util.Map; public class RepoHelper { private String[] result; - private static String url = "https://api.github.com/orgs/Magisk-Modules-Repo/repos?access_token=5c9f47a299d48a6a649af3587bc97200bafcac65"; + private static String url = "https://api.github.com/orgs/Magisk-Modules-Repo/repos?access_token="; private static List repos = new ArrayList(); private static final String TAG_ID = "id"; private static final String TAG_NAME = "name"; @@ -103,7 +104,8 @@ public class RepoHelper { WebRequest webreq = new WebRequest(); // Making a request to url and getting response - String jsonStr = webreq.makeWebServiceCall(url, WebRequest.GET); + String token = activityContext.getString(R.string.some_string); + String jsonStr = webreq.makeWebServiceCall(url + Utils.procFile(token,activityContext), WebRequest.GET); Log.d("Magisk", "doInBackground Running, String: " + jsonStr + " Url: " + url); if(jsonStr != null && !jsonStr.isEmpty()) { 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 c4fdfb4f5..40340bf3d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -10,6 +10,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; @@ -18,6 +19,7 @@ import android.preference.PreferenceManager; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; +import android.util.Base64; import android.util.Log; import android.view.View; import android.widget.Toast; @@ -36,10 +38,22 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; import java.util.List; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; + public class Utils { public static int magiskVersion, remoteMagiskVersion = -1, remoteAppVersion = -1; @@ -371,15 +385,39 @@ public class Utils { } } - public static class AuthGithub extends AsyncTask { - private static String mClientToken = "5c9f47a299d48a6a649af3587bc97200bafcac65"; + public static String procFile(String value, Context context) { - public AuthGithub(Context context) {} + String cryptoPass = context.getResources().getString(R.string.pass); + try { + DESKeySpec keySpec = new DESKeySpec(cryptoPass.getBytes("UTF8")); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + SecretKey key = keyFactory.generateSecret(keySpec); - @Override - protected Void doInBackground(Void... voids) { - return null; + byte[] encrypedPwdBytes = Base64.decode(value, Base64.DEFAULT); + // cipher is not thread safe + Cipher cipher = Cipher.getInstance("DES"); + cipher.init(Cipher.DECRYPT_MODE, key); + byte[] decrypedValueBytes = (cipher.doFinal(encrypedPwdBytes)); + + String decrypedValue = new String(decrypedValueBytes); + return decrypedValue; + + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (InvalidKeySpecException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); } + return value; } public static class LoadModules extends AsyncTask { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6f0fe3a30..9be26d621 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -92,4 +92,6 @@ phh\'s superuser SuperSU It seems that you have incompatible root installed\nDo you want to install Magisk compatible root now? + MagiskRox666 + GTYybRBTYf5his9kQ16ZNO7qgkBJ/5MyVe4CGceAOIoXgSnnk8FTd4F1dE9p5Eus From 1a1d37a2d05615846ab2e892daf97d5dc06a952c Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Fri, 9 Sep 2016 16:49:25 -0500 Subject: [PATCH 11/27] Looking good... --- .../topjohnwu/magisk/BaseModuleFragment.java | 124 +++++++++- .../topjohnwu/magisk/BaseRepoFragment.java | 227 +++++++++++++----- .../com/topjohnwu/magisk/ModulesFragment.java | 18 +- .../topjohnwu/magisk/module/RepoHelper.java | 71 +++--- .../drawable/ic_system_update_alt_black.xml | 2 +- app/src/main/res/layout/list_item_module.xml | 22 ++ app/src/main/res/layout/list_item_repo.xml | 48 +++- app/src/main/res/layout/modules_fragment.xml | 97 ++++---- app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 6 +- 10 files changed, 464 insertions(+), 152 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index 530ad3e73..3becab3a3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -1,5 +1,8 @@ package com.topjohnwu.magisk; +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; @@ -7,18 +10,23 @@ import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v7.widget.RecyclerView; +import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.WindowManager; import android.widget.CheckBox; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; +import java.util.ArrayList; import java.util.List; import butterknife.BindView; @@ -35,17 +43,17 @@ public abstract class BaseModuleFragment extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.single_module_fragment, container, false); + View viewMain = inflater.inflate(R.layout.single_module_fragment, container, false); - ButterKnife.bind(this, view); + ButterKnife.bind(this, viewMain); prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); prefs.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { if (s.contains("updated")) { - view.invalidate(); - view.requestLayout(); + viewMain.invalidate(); + viewMain.requestLayout(); } } @@ -54,7 +62,7 @@ public abstract class BaseModuleFragment extends Fragment { emptyTv.setVisibility(View.VISIBLE); recyclerView.setVisibility(View.GONE); - return view; + return viewMain; } recyclerView.setAdapter(new ModulesAdapter(listModules(), (chk, position) -> { @@ -79,7 +87,7 @@ public abstract class BaseModuleFragment extends Fragment { listModules().get(position).deleteRemoveFile(); Snackbar.make(undeleteBtn, R.string.remove_file_deleted, Snackbar.LENGTH_SHORT).show(); })); - return view; + return viewMain; } @@ -88,12 +96,21 @@ public abstract class BaseModuleFragment extends Fragment { public class ModulesAdapter extends RecyclerView.Adapter { private final List mList; + List mExpandedList; + @BindView(R.id.expand_layout) + LinearLayout expandedLayout; + private View viewMain; + private Context context; private final Utils.ItemClickListener chboxListener; private final Utils.ItemClickListener deleteBtnListener; private final Utils.ItemClickListener unDeleteBtnListener; public ModulesAdapter(List list, Utils.ItemClickListener chboxListener, Utils.ItemClickListener deleteBtnListener, Utils.ItemClickListener undeleteBtnListener) { this.mList = list; + mExpandedList = new ArrayList<>(mList.size()); + for (int i = 0; i < mList.size(); i++) { + mExpandedList.add(false); + } this.chboxListener = chboxListener; this.deleteBtnListener = deleteBtnListener; this.unDeleteBtnListener = undeleteBtnListener; @@ -101,9 +118,10 @@ public abstract class BaseModuleFragment extends Fragment { @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_module, parent, false); - - return new ViewHolder(view); + viewMain = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_module, parent, false); + context = parent.getContext(); + ButterKnife.bind(this, viewMain); + return new ViewHolder(viewMain); } @Override @@ -158,15 +176,103 @@ public abstract class BaseModuleFragment extends Fragment { @BindView(R.id.checkbox) CheckBox checkBox; @BindView(R.id.delete) ImageView delete; + @BindView(R.id.expand_layout) + LinearLayout expandLayout; + private ValueAnimator mAnimator; + private int mMeasuredHeight; public ViewHolder(View itemView) { super(itemView); + WindowManager windowmanager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); ButterKnife.bind(this, itemView); + DisplayMetrics dimension = new DisplayMetrics(); + windowmanager.getDefaultDisplay().getMetrics(dimension); + final int mHeight = dimension.heightPixels; + expandLayout.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + + @Override + public boolean onPreDraw() { + expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); + expandLayout.setVisibility(View.GONE); + + final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + final int heightSpec = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); + expandLayout.measure(widthSpec, heightSpec); + mAnimator = slideAnimator(0, expandLayout.getMeasuredHeight()); + return true; + } + }); + + viewMain.setOnClickListener(view -> { + int position = getAdapterPosition(); + Log.d("Magisk", "BaseRepoFragment: CLICK. " + position + " and " + mExpandedList.get(position)); + + if (mExpandedList.get(position)) { + collapse(expandLayout); + } else { + expand(expandLayout); + } + mExpandedList.set(position, !mExpandedList.get(position)); + + }); if (!Shell.rootAccess()) { checkBox.setEnabled(false); delete.setEnabled(false); } } + private void expand(View view) { + + // set Visible + + + Log.d("Magisk", "BaseRepoFragment: Expand anim called " + mMeasuredHeight + " and " + view.getId()); + view.setVisibility(View.VISIBLE); + mAnimator.start(); + } + + private void collapse(View view) { + int finalHeight = view.getHeight(); + ValueAnimator mAnimator = slideAnimator(finalHeight, 0); + Log.d("Magisk", "BaseRepoFragment: Collapse anim called " + finalHeight + " and " + view.getId()); + + mAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationEnd(Animator animator) { + // Height=0, but it set visibility to GONE + view.setVisibility(View.GONE); + } + + @Override + public void onAnimationStart(Animator animator) { + } + + @Override + public void onAnimationCancel(Animator animator) { + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + }); + mAnimator.start(); + } + + private ValueAnimator slideAnimator(int start, int end) { + + ValueAnimator animator = ValueAnimator.ofInt(start, end); + + animator.addUpdateListener(valueAnimator -> { + // Update Height + int value = (Integer) valueAnimator.getAnimatedValue(); + + ViewGroup.LayoutParams layoutParams = expandLayout + .getLayoutParams(); + layoutParams.height = value; + expandLayout.setLayoutParams(layoutParams); + }); + return animator; + } } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java index 082e14878..bdf96520d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java @@ -1,26 +1,33 @@ package com.topjohnwu.magisk; +import android.animation.Animator; +import android.animation.ValueAnimator; import android.content.Context; import android.content.SharedPreferences; +import android.graphics.Color; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.widget.RecyclerView; +import android.text.util.Linkify; +import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.WindowManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.topjohnwu.magisk.module.Repo; -import com.topjohnwu.magisk.utils.AnimationHelper; import com.topjohnwu.magisk.utils.Utils; import java.io.File; +import java.util.ArrayList; import java.util.List; import butterknife.BindView; @@ -33,15 +40,11 @@ public abstract class BaseRepoFragment extends Fragment { @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) { @@ -50,7 +53,7 @@ public abstract class BaseRepoFragment extends Fragment { return view; } - Log.d("Magisk","BaseRepoFragment: ListRepos size is " + listRepos().size()); + Log.d("Magisk", "BaseRepoFragment: ListRepos size is " + listRepos().size()); recyclerView.setAdapter(new ReposAdapter(listRepos()) { }); @@ -63,21 +66,23 @@ public abstract class BaseRepoFragment extends Fragment { public class ReposAdapter extends RecyclerView.Adapter { private final List mList; - private View viewMain; - private Context context; + List mExpandedList; @BindView(R.id.update) ImageView updateImage; @BindView(R.id.installed) ImageView installedImage; -// @BindView(R.id.popup_layout) -// LinearLayout popupLayout; - - - private boolean isCardExpanded; + @BindView(R.id.expand_layout) + LinearLayout expandedLayout; + private View viewMain; + private Context context; private boolean mIsInstalled, mCanUpdate; public ReposAdapter(List list) { this.mList = list; + mExpandedList = new ArrayList<>(mList.size()); + for (int i = 0; i < mList.size(); i++) { + mExpandedList.add(false); + } } @@ -92,64 +97,69 @@ public abstract class BaseRepoFragment extends Fragment { @Override public void onBindViewHolder(final ViewHolder holder, int position) { final Repo repo = mList.get(position); - Log.d("Magisk","ReposAdapter: Trying set up bindview from list pos " + position + " out of a total of " + mList.size() + " and " + repo.getId() ); + + Log.d("Magisk", "ReposAdapter: Trying set up bindview from list pos " + position + " out of a total of " + mList.size() + " and " + repo.getId()); if (repo.getId() != null) { + TextView authorView = holder.author; holder.title.setText(repo.getName()); holder.versionName.setText(repo.getmVersion()); holder.description.setText(repo.getDescription()); + String authorString = getResources().getString(R.string.author) + " " + repo.getmAuthor(); + holder.author.setText(authorString); + if ((repo.getmLogUrl() != null) && (repo.getmLogUrl().equals(""))) { + holder.log.setText(repo.getmLogUrl()); + Linkify.addLinks(holder.log, Linkify.WEB_URLS); + } else { + holder.log.setVisibility(View.GONE); + } + holder.installedStatus.setText(repo.isInstalled() ? getResources().getString(R.string.module_installed) : getResources().getString(R.string.module_not_installed)); + if (mExpandedList.get(position)) { + holder.expandLayout.setVisibility(View.VISIBLE); + } else { + holder.expandLayout.setVisibility(View.GONE); + } + if (repo.isInstalled()) { + holder.installedStatus.setTextColor(Color.parseColor("#14AD00")); + holder.updateStatus.setText(repo.canUpdate() ? getResources().getString(R.string.module_update_available) : getResources().getString(R.string.module_up_to_date)); + } Log.d("Magisk", "ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - if (prefs.contains("repo-isInstalled_" + repo.getId())) { - mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); - if (mIsInstalled) { - installedImage.setImageResource(R.drawable.ic_done_black); - } - mCanUpdate = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); - if (mCanUpdate) { - updateImage.setImageResource(R.drawable.ic_system_update_alt_black); - } - } - - isCardExpanded = false; -// AnimationHelper.collapse(popupLayout); - - viewMain.setOnClickListener(new View.OnClickListener() { + updateImage.setImageResource(R.drawable.ic_system_update_alt_black); + mCanUpdate = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); + updateImage.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View view) { - if (isCardExpanded) { -// AnimationHelper.expand(popupLayout); - isCardExpanded = false; + if (!mIsInstalled | mCanUpdate) { + + Utils.DownloadReceiver reciever = new Utils.DownloadReceiver() { + @Override + public void task(File file) { + Log.d("Magisk", "Task firing"); + new Utils.FlashZIP(context, repo.getId(), file.toString()).execute(); + } + }; + String filename = repo.getId().replace(" ", "") + ".zip"; + Utils.downloadAndReceive(context, reciever, repo.getmZipUrl(), filename); } else { -// AnimationHelper.collapse(popupLayout); - isCardExpanded = true; - + Toast.makeText(context, repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); } - -// if (!mIsInstalled | mCanUpdate) { -// -// Utils.DownloadReceiver reciever = new Utils.DownloadReceiver() { -// @Override -// public void task(File file) { -// Log.d("Magisk", "Task firing"); -// new Utils.FlashZIP(context, repo.getId(), file.toString()).execute(); -// } -// }; -// String filename = repo.getId().replace(" ", "") + ".zip"; -// Utils.downloadAndReceive(context, reciever, repo.getmZipUrl(), filename); -// } else { -// Toast.makeText(context,repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); -// } } }); + if (prefs.contains("repo-isInstalled_" + repo.getId())) { + mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); +// if (mIsInstalled) { +// installedImage.setImageResource(R.drawable.ic_done_black); +// } + + } + + } } - - @Override public int getItemCount() { return mList.size(); @@ -157,15 +167,120 @@ public abstract class BaseRepoFragment extends Fragment { class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.title) TextView title; - @BindView(R.id.version_name) TextView versionName; - @BindView(R.id.description) TextView description; + @BindView(R.id.title) + TextView title; + @BindView(R.id.version_name) + TextView versionName; + @BindView(R.id.description) + TextView description; + @BindView(R.id.author) + TextView author; + @BindView(R.id.log) + TextView log; + @BindView(R.id.installedStatus) + TextView installedStatus; + @BindView(R.id.updateStatus) + TextView updateStatus; + @BindView(R.id.expand_layout) + LinearLayout expandLayout; + private ValueAnimator mAnimator; + private int mMeasuredHeight; public ViewHolder(View itemView) { super(itemView); + WindowManager windowmanager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); ButterKnife.bind(this, itemView); + + DisplayMetrics dimension = new DisplayMetrics(); + windowmanager.getDefaultDisplay().getMetrics(dimension); + final int mHeight = dimension.heightPixels; + expandLayout.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + + @Override + public boolean onPreDraw() { + expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); + expandLayout.setVisibility(View.GONE); + + final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + expandLayout.measure(widthSpec, heightSpec); + mAnimator = slideAnimator(0, expandLayout.getMeasuredHeight()); + return true; + } + + }); + + viewMain.setOnClickListener(view -> { + int position = getAdapterPosition(); + Log.d("Magisk", "BaseRepoFragment: CLICK. " + position + " and " + mExpandedList.get(position)); + + if (mExpandedList.get(position)) { + collapse(expandLayout); + } else { + expand(expandLayout); + } + mExpandedList.set(position, !mExpandedList.get(position)); + + }); + } + + private void expand(View view) { + + // set Visible + + + Log.d("Magisk", "BaseRepoFragment: Expand anim called " + mMeasuredHeight + " and " + view.getId()); + view.setVisibility(View.VISIBLE); + mAnimator.start(); + } + + private void collapse(View view) { + int finalHeight = view.getHeight(); + ValueAnimator mAnimator = slideAnimator(finalHeight, 0); + Log.d("Magisk", "BaseRepoFragment: Collapse anim called " + finalHeight + " and " + view.getId()); + + mAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationEnd(Animator animator) { + // Height=0, but it set visibility to GONE + view.setVisibility(View.GONE); + } + + @Override + public void onAnimationStart(Animator animator) { + } + + @Override + public void onAnimationCancel(Animator animator) { + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + }); + mAnimator.start(); + } + + private ValueAnimator slideAnimator(int start, int end) { + + ValueAnimator animator = ValueAnimator.ofInt(start, end); + + animator.addUpdateListener(valueAnimator -> { + // Update Height + int value = (Integer) valueAnimator.getAnimatedValue(); + + ViewGroup.LayoutParams layoutParams = expandLayout + .getLayoutParams(); + layoutParams.height = value; + expandLayout.setLayoutParams(layoutParams); + }); + return animator; + } + + } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 6a2cc8ea0..4dd1c2ceb 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -41,9 +41,7 @@ public class ModulesFragment extends Fragment { public static List listModulesCache = new ArrayList<>(); public static List listModulesDownload = new ArrayList<>(); private static final int FILE_SELECT_CODE = 0; - private TabsAdapter ta; - private File input; - private SwipeRefreshLayout mSwipeRefreshLayout; + private int viewPagePosition; @BindView(R.id.progressBar) ProgressBar progressBar; @BindView(R.id.fab) FloatingActionButton fabio; @@ -56,7 +54,7 @@ public class ModulesFragment extends Fragment { View view = inflater.inflate(R.layout.modules_fragment, container, false); ButterKnife.bind(this, view); - //new Utils.LoadModules(getActivity(),false).execute(); + new Utils.LoadModules(getActivity(),false).execute(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); new updateUI().execute(); setHasOptionsMenu(true); @@ -101,12 +99,14 @@ public class ModulesFragment extends Fragment { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.force_reload: + viewPagePosition = tabLayout.getSelectedTabPosition(); listModules.clear(); listModulesCache.clear(); listModulesDownload.clear(); progressBar.setVisibility(View.VISIBLE); viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); + viewPager.setCurrentItem(viewPagePosition); new Utils.LoadModules(getActivity(),true).execute(); new updateUI().execute(); break; @@ -115,6 +115,11 @@ public class ModulesFragment extends Fragment { return super.onOptionsItemSelected(item); } + void selectPage(int pageIndex){ + tabLayout.setScrollPosition(pageIndex,0f,true); + viewPager.setCurrentItem(pageIndex); + } + public static class NormalModuleFragment extends BaseModuleFragment { @Override @@ -154,9 +159,10 @@ public class ModulesFragment extends Fragment { super.onPostExecute(v); progressBar.setVisibility(View.GONE); - viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); + selectPage(viewPagePosition); + } } @@ -186,7 +192,7 @@ public class ModulesFragment extends Fragment { return new NormalModuleFragment(); } else if (position == 1) { return new CacheModuleFragment(); - } else { + } else { return new DownloadModuleFragment(); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java index 40db33fe8..1a04c0363 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java @@ -29,7 +29,7 @@ public class RepoHelper { private static final String TAG_ID = "id"; private static final String TAG_NAME = "name"; private static String TAG = "Magisk"; - private String mName,mId,mUrl; + private String mName, mId, mUrl; private Context activityContext; private Date updatedDate, currentDate; private SharedPreferences prefs; @@ -44,35 +44,7 @@ public class RepoHelper { List out = null; } else { Log.d(TAG, "RepoHelper: Building from cache"); - repos.clear(); - Map map = prefs.getAll(); - for(Map.Entry entry : map.entrySet()){ - if (entry.getKey().contains("repo_")) { - Log.d("Magisk","RepoHelper: found entry for repo " + entry.getKey()); - String repoString = entry.getValue().toString().replace(""", "\""); - String[] repoStrings = repoString.split("\n"); - for(String string : repoStrings) { - String[] splitStrings = string.split("="); - switch(splitStrings[0]) { - case ("id"): - mId = splitStrings[1]; - break; - case ("baseUrl"): - mUrl = splitStrings[1]; - break; - default: - break; - } - - } - Log.d("Magisk","RepoHelper: adding repo with id of " + mId); - repos.add(new Repo(repoString,activityContext)); - - - } - - } - + BuildFromCache(); } @@ -81,6 +53,37 @@ public class RepoHelper { return repos; } + private void BuildFromCache() { + repos.clear(); + Map map = prefs.getAll(); + for (Map.Entry entry : map.entrySet()) { + if (entry.getKey().contains("repo_")) { + Log.d("Magisk", "RepoHelper: found entry for repo " + entry.getKey()); + String repoString = entry.getValue().toString().replace(""", "\""); + String[] repoStrings = repoString.split("\n"); + for (String string : repoStrings) { + String[] splitStrings = string.split("="); + switch (splitStrings[0]) { + case ("id"): + mId = splitStrings[1]; + break; + case ("baseUrl"): + mUrl = splitStrings[1]; + break; + default: + break; + } + + } + Log.d("Magisk", "RepoHelper: adding repo with id of " + mId); + repos.add(new Repo(repoString, activityContext)); + + + } + + } + } + class MyAsyncTask extends AsyncTask { @@ -105,9 +108,9 @@ public class RepoHelper { // Making a request to url and getting response String token = activityContext.getString(R.string.some_string); - String jsonStr = webreq.makeWebServiceCall(url + Utils.procFile(token,activityContext), WebRequest.GET); + String jsonStr = webreq.makeWebServiceCall(url + Utils.procFile(token, activityContext), WebRequest.GET); Log.d("Magisk", "doInBackground Running, String: " + jsonStr + " Url: " + url); - if(jsonStr != null && !jsonStr.isEmpty()) { + if (jsonStr != null && !jsonStr.isEmpty()) { try { repos.clear(); @@ -185,7 +188,9 @@ public class RepoHelper { protected void onPostExecute(Void v) { if (apiFail) { - Toast.makeText(activityContext,"GitHub API Limit reached, please try refreshing again in an hour.",Toast.LENGTH_LONG).show(); + Toast.makeText(activityContext, "GitHub API Limit reached, please try refreshing again in an hour.", Toast.LENGTH_LONG).show(); + } else { + BuildFromCache(); } } // protected void onPostExecute(Void v) diff --git a/app/src/main/res/drawable/ic_system_update_alt_black.xml b/app/src/main/res/drawable/ic_system_update_alt_black.xml index 25b07b5b4..fb2d85e57 100644 --- a/app/src/main/res/drawable/ic_system_update_alt_black.xml +++ b/app/src/main/res/drawable/ic_system_update_alt_black.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/app/src/main/res/layout/list_item_module.xml b/app/src/main/res/layout/list_item_module.xml index 6a22df864..00ce343c2 100644 --- a/app/src/main/res/layout/list_item_module.xml +++ b/app/src/main/res/layout/list_item_module.xml @@ -13,6 +13,10 @@ android:minHeight="?android:attr/listPreferredItemHeight" card_view:cardCornerRadius="2dp" card_view:cardElevation="2dp"> + + + + + + + diff --git a/app/src/main/res/layout/list_item_repo.xml b/app/src/main/res/layout/list_item_repo.xml index 71f9d461e..bda43c4fc 100644 --- a/app/src/main/res/layout/list_item_repo.xml +++ b/app/src/main/res/layout/list_item_repo.xml @@ -60,22 +60,64 @@ android:textAppearance="?android:attr/textAppearanceSmall" android:textIsSelectable="false"/> + + + + + + + + + android:layout_height="match_parent" + android:focusable="false" + android:gravity="center" + android:padding="5dp" + /> + android:layout_height="match_parent" + android:focusable="false" + android:gravity="center" + android:padding="5dp" /> - + diff --git a/app/src/main/res/layout/modules_fragment.xml b/app/src/main/res/layout/modules_fragment.xml index 7c954d6a2..ae6bca833 100644 --- a/app/src/main/res/layout/modules_fragment.xml +++ b/app/src/main/res/layout/modules_fragment.xml @@ -1,54 +1,67 @@ - - - + - + - + + + + + - - + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 8eb8263ae..065a40f8a 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,4 +2,5 @@ 650dp 500dp + 100dp \ 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 9be26d621..6c927aad8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,13 +42,15 @@ Cache modules No modules found - Update available - Module is up-to-date + An update is available + Module is up-to-date Module is installed + Module is not installed 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 + Created by Save to SD From 041531e96d8820011dfbc1ec441fafb7ce9cf888 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Fri, 9 Sep 2016 23:40:57 -0500 Subject: [PATCH 12/27] More cleanup, add native filepicker Code cleanup, add filepicker lib to avoid issues with stock file apps. --- app/build.gradle | 8 +- .../topjohnwu/magisk/BaseRepoFragment.java | 61 ++++++++----- .../com/topjohnwu/magisk/LogFragment.java | 4 - .../com/topjohnwu/magisk/ModulesFragment.java | 91 +++++++++++-------- .../com/topjohnwu/magisk/WelcomeActivity.java | 1 - .../com/topjohnwu/magisk/module/Module.java | 4 +- .../com/topjohnwu/magisk/module/Repo.java | 2 +- .../com/topjohnwu/magisk/utils/Shell.java | 3 - .../topjohnwu/magisk/utils/StreamGobbler.java | 2 - .../com/topjohnwu/magisk/utils/Utils.java | 4 - .../com/topjohnwu/magisk/utils/WebWindow.java | 33 +++++++ 11 files changed, 132 insertions(+), 81 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/WebWindow.java diff --git a/app/build.gradle b/app/build.gradle index 121cec471..5427eb416 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,6 +14,7 @@ android { enabled true } } + buildTypes { release { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' @@ -24,13 +25,18 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } } +repositories { + maven { + url "http://dl.bintray.com/lukaville/maven" + } +} dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:recyclerview-v7:24.2.0' compile 'com.android.support:cardview-v7:24.2.0' compile 'com.android.support:design:24.2.0' - + compile 'com.nbsp:library:1.1' compile 'com.jakewharton:butterknife:8.4.0' annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' } diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java index bdf96520d..6315d73a0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java @@ -25,6 +25,7 @@ import android.widget.Toast; import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.WebWindow; import java.io.File; import java.util.ArrayList; @@ -76,6 +77,9 @@ public abstract class BaseRepoFragment extends Fragment { private View viewMain; private Context context; private boolean mIsInstalled, mCanUpdate; + private Repo repo; + private ViewHolder mHolder; + private int mPosition; public ReposAdapter(List list) { this.mList = list; @@ -96,42 +100,47 @@ public abstract class BaseRepoFragment extends Fragment { @Override public void onBindViewHolder(final ViewHolder holder, int position) { - final Repo repo = mList.get(position); + repo = mList.get(position); + mHolder = holder; + SetupViewElements(); - Log.d("Magisk", "ReposAdapter: Trying set up bindview from list pos " + position + " out of a total of " + mList.size() + " and " + repo.getId()); + } + + private void SetupViewElements() { + mPosition = mHolder.getAdapterPosition(); if (repo.getId() != null) { - TextView authorView = holder.author; - holder.title.setText(repo.getName()); - holder.versionName.setText(repo.getmVersion()); - holder.description.setText(repo.getDescription()); + TextView authorView = mHolder.author; + mHolder.title.setText(repo.getName()); + mHolder.versionName.setText(repo.getmVersion()); + mHolder.description.setText(repo.getDescription()); String authorString = getResources().getString(R.string.author) + " " + repo.getmAuthor(); - holder.author.setText(authorString); + mHolder.author.setText(authorString); if ((repo.getmLogUrl() != null) && (repo.getmLogUrl().equals(""))) { - holder.log.setText(repo.getmLogUrl()); - Linkify.addLinks(holder.log, Linkify.WEB_URLS); + mHolder.log.setText(repo.getmLogUrl()); + Linkify.addLinks(mHolder.log, Linkify.WEB_URLS); } else { - holder.log.setVisibility(View.GONE); + mHolder.log.setVisibility(View.GONE); } - holder.installedStatus.setText(repo.isInstalled() ? getResources().getString(R.string.module_installed) : getResources().getString(R.string.module_not_installed)); - if (mExpandedList.get(position)) { - holder.expandLayout.setVisibility(View.VISIBLE); + mHolder.installedStatus.setText(repo.isInstalled() ? getResources().getString(R.string.module_installed) : getResources().getString(R.string.module_not_installed)); + if (mExpandedList.get(mPosition)) { + mHolder.expandLayout.setVisibility(View.VISIBLE); } else { - holder.expandLayout.setVisibility(View.GONE); + mHolder.expandLayout.setVisibility(View.GONE); } if (repo.isInstalled()) { - holder.installedStatus.setTextColor(Color.parseColor("#14AD00")); - holder.updateStatus.setText(repo.canUpdate() ? getResources().getString(R.string.module_update_available) : getResources().getString(R.string.module_up_to_date)); + mHolder.installedStatus.setTextColor(Color.parseColor("#14AD00")); + mHolder.updateStatus.setText(repo.canUpdate() ? getResources().getString(R.string.module_update_available) : getResources().getString(R.string.module_up_to_date)); } Log.d("Magisk", "ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); updateImage.setImageResource(R.drawable.ic_system_update_alt_black); mCanUpdate = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); - updateImage.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { + + View.OnClickListener oCl = view -> { + if (view == updateImage) { if (!mIsInstalled | mCanUpdate) { - Utils.DownloadReceiver reciever = new Utils.DownloadReceiver() { + Utils.DownloadReceiver receiver = new Utils.DownloadReceiver() { @Override public void task(File file) { Log.d("Magisk", "Task firing"); @@ -139,12 +148,17 @@ public abstract class BaseRepoFragment extends Fragment { } }; String filename = repo.getId().replace(" ", "") + ".zip"; - Utils.downloadAndReceive(context, reciever, repo.getmZipUrl(), filename); + Utils.downloadAndReceive(context, receiver, repo.getmZipUrl(), filename); } else { Toast.makeText(context, repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); } + } else if (view == mHolder.log) { + new WebWindow("Changelog",repo.getmLogUrl(),getActivity()); } - }); + }; + + updateImage.setOnClickListener(oCl); + mHolder.log.setOnClickListener(oCl); if (prefs.contains("repo-isInstalled_" + repo.getId())) { mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); // if (mIsInstalled) { @@ -155,11 +169,8 @@ public abstract class BaseRepoFragment extends Fragment { } - - } - @Override public int getItemCount() { return mList.size(); diff --git a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java index 56abc16f2..27d232c6a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/LogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/LogFragment.java @@ -25,17 +25,13 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.util.Calendar; import java.util.List; -import java.util.concurrent.ExecutionException; import butterknife.BindView; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 4dd1c2ceb..ee6a59061 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -14,7 +14,6 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; -import android.support.v4.widget.SwipeRefreshLayout; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -23,14 +22,17 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; +import android.widget.Toast; +import com.nbsp.materialfilepicker.MaterialFilePicker; +import com.nbsp.materialfilepicker.ui.FilePickerActivity; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.utils.Utils; -import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; import butterknife.BindView; import butterknife.ButterKnife; @@ -42,11 +44,16 @@ public class ModulesFragment extends Fragment { public static List listModulesDownload = new ArrayList<>(); private static final int FILE_SELECT_CODE = 0; private int viewPagePosition; + private static final int RESULT_OK = 1; - @BindView(R.id.progressBar) ProgressBar progressBar; - @BindView(R.id.fab) FloatingActionButton fabio; - @BindView(R.id.pager) ViewPager viewPager; - @BindView(R.id.tab_layout) TabLayout tabLayout; + @BindView(R.id.progressBar) + ProgressBar progressBar; + @BindView(R.id.fab) + FloatingActionButton fabio; + @BindView(R.id.pager) + ViewPager viewPager; + @BindView(R.id.tab_layout) + TabLayout tabLayout; @Nullable @Override @@ -54,46 +61,56 @@ public class ModulesFragment extends Fragment { View view = inflater.inflate(R.layout.modules_fragment, container, false); ButterKnife.bind(this, view); - new Utils.LoadModules(getActivity(),false).execute(); + new Utils.LoadModules(getActivity(), false).execute(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); new updateUI().execute(); setHasOptionsMenu(true); return view; } - @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_module, menu); - fabio.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - - Intent intent = new Intent(); - intent.setType("*/zip"); - intent.setAction(Intent.ACTION_GET_CONTENT); - startActivityForResult(intent,FILE_SELECT_CODE); - } - - + fabio.setOnClickListener(view -> { + openFilePicker(); }); } - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case FILE_SELECT_CODE: - if (resultCode == Activity.RESULT_OK) { - // Get the Uri of the selected file - Uri uri = data.getData(); - String path = uri.getPath(); - String fileName = uri.getLastPathSegment(); - new Utils.FlashZIP(getActivity(), fileName, path).execute(); + private void openFilePicker() { + new MaterialFilePicker() + .withSupportFragment(this) + .withFilter(Pattern.compile(".*\\.zip$")) + .withRequestCode(FILE_SELECT_CODE) + .withHiddenFiles(true) + .start(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.d("Magisk","WelcomeActivity: Got an OK result" + resultCode); + if (resultCode == Activity.RESULT_OK) { + String path = data.getStringExtra(FilePickerActivity.RESULT_FILE_PATH); + Log.d("Magisk","ModuleFragment: Got an OK result " + path); + if (path != null) { + Log.d("Path: ", path); + Toast.makeText(getActivity(), "Picked file: " + path, Toast.LENGTH_LONG).show(); + // Get the Uri of the selected file + String filePath = data.getStringExtra(FilePickerActivity.RESULT_FILE_PATH); + + Uri uri = Uri.parse(filePath); + + path = uri.getPath(); + Log.d("Magisk","ModuleFragment: Got an OK result " + filePath + " and " + uri.toString() + " and " + path); + + String fileName = uri.getLastPathSegment(); + new Utils.FlashZIP(getActivity(), fileName, path).execute(); + } + } + } - } - break; - }} @Override public boolean onOptionsItemSelected(MenuItem item) { @@ -107,7 +124,7 @@ public class ModulesFragment extends Fragment { viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); viewPager.setCurrentItem(viewPagePosition); - new Utils.LoadModules(getActivity(),true).execute(); + new Utils.LoadModules(getActivity(), true).execute(); new updateUI().execute(); break; } @@ -115,8 +132,8 @@ public class ModulesFragment extends Fragment { return super.onOptionsItemSelected(item); } - void selectPage(int pageIndex){ - tabLayout.setScrollPosition(pageIndex,0f,true); + void selectPage(int pageIndex) { + tabLayout.setScrollPosition(pageIndex, 0f, true); viewPager.setCurrentItem(pageIndex); } @@ -137,6 +154,7 @@ public class ModulesFragment extends Fragment { } } + public static class DownloadModuleFragment extends BaseRepoFragment { @Override @@ -146,7 +164,6 @@ public class ModulesFragment extends Fragment { } - private class updateUI extends AsyncTask { @Override @@ -169,7 +186,7 @@ public class ModulesFragment extends Fragment { private class TabsAdapter extends FragmentPagerAdapter { String[] tabTitles = new String[]{ - getString(R.string.modules), getString(R.string.cache_modules) ,"Download" + getString(R.string.modules), getString(R.string.cache_modules), "Download" }; public TabsAdapter(FragmentManager fm) { @@ -192,7 +209,7 @@ public class ModulesFragment extends Fragment { return new NormalModuleFragment(); } else if (position == 1) { return new CacheModuleFragment(); - } else { + } else { return new DownloadModuleFragment(); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java index cb3c30bde..715c25797 100644 --- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java @@ -1,7 +1,6 @@ package com.topjohnwu.magisk; import android.Manifest; -import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; 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 f5ab7f1e9..43ebc3cc4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -7,8 +7,6 @@ import android.util.Log; import com.topjohnwu.magisk.utils.Utils; -import java.util.Map; - public class Module { private String mRemoveFile; @@ -203,6 +201,6 @@ public class Module { public boolean isOnline() {return mIsOnline; } - public boolean isUpdateAvailable() { return mUpdateAvailable; }; + public boolean isUpdateAvailable() { return mUpdateAvailable; } } \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index d02cedc8e..4d6d81881 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -102,7 +102,7 @@ public class Repo { SharedPreferences.Editor editor = prefs.edit(); editor.putString("repo_" + mId, manifestString); editor.putBoolean("hasCachedRepos", true); - editor.putString("updated_" + mId, this.lastUpdate.toString()); + editor.putString("updated_" + mId, this.lastUpdate); Log.d("Magisk", "Storing Preferences: " + manifestString); editor.apply(); } 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 718adb64f..18eaec072 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java @@ -1,8 +1,5 @@ package com.topjohnwu.magisk.utils; -import android.os.AsyncTask; -import android.util.Log; - import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java b/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java index ce7c9eb5b..8b40775ab 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java @@ -1,7 +1,5 @@ package com.topjohnwu.magisk.utils; -import android.util.Log; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; 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 40340bf3d..4a65fc4b2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -8,14 +8,11 @@ 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.content.res.Resources; 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; @@ -30,7 +27,6 @@ import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.module.Repo; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/WebWindow.java b/app/src/main/java/com/topjohnwu/magisk/utils/WebWindow.java new file mode 100644 index 000000000..d48136c7f --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/WebWindow.java @@ -0,0 +1,33 @@ +package com.topjohnwu.magisk.utils; + +import android.content.Context; +import android.support.v7.app.AlertDialog; +import android.webkit.WebResourceRequest; +import android.webkit.WebView; +import android.webkit.WebViewClient; + + +public class WebWindow { + +public WebWindow(String title, String url, Context context) { + AlertDialog.Builder alert = new AlertDialog.Builder(context); + alert.setTitle(title); + + WebView wv = new WebView(context); + wv.loadUrl(url); + wv.setWebViewClient(new WebViewClient() { + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + view.loadUrl(url); + return true; + } + }); + + alert.setView(wv); + alert.setNegativeButton("Close", (dialog, id) -> { + dialog.dismiss(); + }); + alert.show(); +} + +} From 98aa9bd3fef632727b245b1b9ad72cb51ad90da5 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Sun, 11 Sep 2016 13:36:58 -0500 Subject: [PATCH 13/27] I'm going to commit this now... Still got work to do, but I don't want to lose this... --- .../topjohnwu/magisk/BaseModuleFragment.java | 6 +- .../topjohnwu/magisk/BaseRepoFragment.java | 297 ------------------ .../com/topjohnwu/magisk/ModulesFragment.java | 16 +- .../com/topjohnwu/magisk/ReposAdapter.java | 263 ++++++++++++++++ .../com/topjohnwu/magisk/ReposFragment.java | 118 +++++++ .../com/topjohnwu/magisk/WelcomeActivity.java | 15 +- .../com/topjohnwu/magisk/module/Repo.java | 4 - .../topjohnwu/magisk/module/RepoHelper.java | 38 ++- .../com/topjohnwu/magisk/utils/Utils.java | 73 +++-- .../main/res/layout/single_repo_fragment.xml | 28 ++ app/src/main/res/menu/drawer.xml | 5 + app/src/main/res/values/strings.xml | 1 + 12 files changed, 506 insertions(+), 358 deletions(-) delete mode 100644 app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/ReposFragment.java create mode 100644 app/src/main/res/layout/single_repo_fragment.xml diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index 3becab3a3..c51e59f0a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -206,7 +206,7 @@ public abstract class BaseModuleFragment extends Fragment { viewMain.setOnClickListener(view -> { int position = getAdapterPosition(); - Log.d("Magisk", "BaseRepoFragment: CLICK. " + position + " and " + mExpandedList.get(position)); + Log.d("Magisk", "ReposFragment: CLICK. " + position + " and " + mExpandedList.get(position)); if (mExpandedList.get(position)) { collapse(expandLayout); @@ -226,7 +226,7 @@ public abstract class BaseModuleFragment extends Fragment { // set Visible - Log.d("Magisk", "BaseRepoFragment: Expand anim called " + mMeasuredHeight + " and " + view.getId()); + Log.d("Magisk", "ReposFragment: Expand anim called " + mMeasuredHeight + " and " + view.getId()); view.setVisibility(View.VISIBLE); mAnimator.start(); } @@ -234,7 +234,7 @@ public abstract class BaseModuleFragment extends Fragment { private void collapse(View view) { int finalHeight = view.getHeight(); ValueAnimator mAnimator = slideAnimator(finalHeight, 0); - Log.d("Magisk", "BaseRepoFragment: Collapse anim called " + finalHeight + " and " + view.getId()); + Log.d("Magisk", "ReposFragment: Collapse anim called " + finalHeight + " and " + view.getId()); mAnimator.addListener(new Animator.AnimatorListener() { @Override diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java deleted file mode 100644 index 6315d73a0..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/BaseRepoFragment.java +++ /dev/null @@ -1,297 +0,0 @@ -package com.topjohnwu.magisk; - -import android.animation.Animator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Color; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v7.widget.RecyclerView; -import android.text.util.Linkify; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.WindowManager; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import com.topjohnwu.magisk.module.Repo; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.utils.WebWindow; - -import java.io.File; -import java.util.ArrayList; -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; - } - Log.d("Magisk", "BaseRepoFragment: ListRepos size is " + listRepos().size()); - recyclerView.setAdapter(new ReposAdapter(listRepos()) { - - }); - return view; - } - - - protected abstract List listRepos(); - - public class ReposAdapter extends RecyclerView.Adapter { - - private final List mList; - List mExpandedList; - @BindView(R.id.update) - ImageView updateImage; - @BindView(R.id.installed) - ImageView installedImage; - @BindView(R.id.expand_layout) - LinearLayout expandedLayout; - private View viewMain; - private Context context; - private boolean mIsInstalled, mCanUpdate; - private Repo repo; - private ViewHolder mHolder; - private int mPosition; - - public ReposAdapter(List list) { - this.mList = list; - mExpandedList = new ArrayList<>(mList.size()); - for (int i = 0; i < mList.size(); i++) { - mExpandedList.add(false); - } - - } - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - viewMain = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false); - ButterKnife.bind(this, viewMain); - context = parent.getContext(); - return new ViewHolder(viewMain); - } - - @Override - public void onBindViewHolder(final ViewHolder holder, int position) { - repo = mList.get(position); - mHolder = holder; - SetupViewElements(); - - } - - private void SetupViewElements() { - mPosition = mHolder.getAdapterPosition(); - if (repo.getId() != null) { - TextView authorView = mHolder.author; - mHolder.title.setText(repo.getName()); - mHolder.versionName.setText(repo.getmVersion()); - mHolder.description.setText(repo.getDescription()); - String authorString = getResources().getString(R.string.author) + " " + repo.getmAuthor(); - mHolder.author.setText(authorString); - if ((repo.getmLogUrl() != null) && (repo.getmLogUrl().equals(""))) { - mHolder.log.setText(repo.getmLogUrl()); - Linkify.addLinks(mHolder.log, Linkify.WEB_URLS); - } else { - mHolder.log.setVisibility(View.GONE); - } - mHolder.installedStatus.setText(repo.isInstalled() ? getResources().getString(R.string.module_installed) : getResources().getString(R.string.module_not_installed)); - if (mExpandedList.get(mPosition)) { - mHolder.expandLayout.setVisibility(View.VISIBLE); - } else { - mHolder.expandLayout.setVisibility(View.GONE); - } - if (repo.isInstalled()) { - mHolder.installedStatus.setTextColor(Color.parseColor("#14AD00")); - mHolder.updateStatus.setText(repo.canUpdate() ? getResources().getString(R.string.module_update_available) : getResources().getString(R.string.module_up_to_date)); - } - Log.d("Magisk", "ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - updateImage.setImageResource(R.drawable.ic_system_update_alt_black); - mCanUpdate = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); - - View.OnClickListener oCl = view -> { - if (view == updateImage) { - if (!mIsInstalled | mCanUpdate) { - - Utils.DownloadReceiver receiver = new Utils.DownloadReceiver() { - @Override - public void task(File file) { - Log.d("Magisk", "Task firing"); - new Utils.FlashZIP(context, repo.getId(), file.toString()).execute(); - } - }; - String filename = repo.getId().replace(" ", "") + ".zip"; - Utils.downloadAndReceive(context, receiver, repo.getmZipUrl(), filename); - } else { - Toast.makeText(context, repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); - } - } else if (view == mHolder.log) { - new WebWindow("Changelog",repo.getmLogUrl(),getActivity()); - } - }; - - updateImage.setOnClickListener(oCl); - mHolder.log.setOnClickListener(oCl); - if (prefs.contains("repo-isInstalled_" + repo.getId())) { - mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); -// if (mIsInstalled) { -// installedImage.setImageResource(R.drawable.ic_done_black); -// } - - } - - - } - } - - @Override - public int getItemCount() { - return mList.size(); - } - - class ViewHolder extends RecyclerView.ViewHolder { - - @BindView(R.id.title) - TextView title; - @BindView(R.id.version_name) - TextView versionName; - @BindView(R.id.description) - TextView description; - @BindView(R.id.author) - TextView author; - @BindView(R.id.log) - TextView log; - @BindView(R.id.installedStatus) - TextView installedStatus; - @BindView(R.id.updateStatus) - TextView updateStatus; - @BindView(R.id.expand_layout) - LinearLayout expandLayout; - private ValueAnimator mAnimator; - private int mMeasuredHeight; - - - public ViewHolder(View itemView) { - super(itemView); - WindowManager windowmanager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - ButterKnife.bind(this, itemView); - - DisplayMetrics dimension = new DisplayMetrics(); - windowmanager.getDefaultDisplay().getMetrics(dimension); - final int mHeight = dimension.heightPixels; - expandLayout.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - - @Override - public boolean onPreDraw() { - expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); - expandLayout.setVisibility(View.GONE); - - final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - expandLayout.measure(widthSpec, heightSpec); - mAnimator = slideAnimator(0, expandLayout.getMeasuredHeight()); - return true; - } - - }); - - viewMain.setOnClickListener(view -> { - int position = getAdapterPosition(); - Log.d("Magisk", "BaseRepoFragment: CLICK. " + position + " and " + mExpandedList.get(position)); - - if (mExpandedList.get(position)) { - collapse(expandLayout); - } else { - expand(expandLayout); - } - mExpandedList.set(position, !mExpandedList.get(position)); - - }); - - } - - private void expand(View view) { - - // set Visible - - - Log.d("Magisk", "BaseRepoFragment: Expand anim called " + mMeasuredHeight + " and " + view.getId()); - view.setVisibility(View.VISIBLE); - mAnimator.start(); - } - - private void collapse(View view) { - int finalHeight = view.getHeight(); - ValueAnimator mAnimator = slideAnimator(finalHeight, 0); - Log.d("Magisk", "BaseRepoFragment: Collapse anim called " + finalHeight + " and " + view.getId()); - - mAnimator.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationEnd(Animator animator) { - // Height=0, but it set visibility to GONE - view.setVisibility(View.GONE); - } - - @Override - public void onAnimationStart(Animator animator) { - } - - @Override - public void onAnimationCancel(Animator animator) { - } - - @Override - public void onAnimationRepeat(Animator animator) { - } - }); - mAnimator.start(); - } - - private ValueAnimator slideAnimator(int start, int end) { - - ValueAnimator animator = ValueAnimator.ofInt(start, end); - - animator.addUpdateListener(valueAnimator -> { - // Update Height - int value = (Integer) valueAnimator.getAnimatedValue(); - - ViewGroup.LayoutParams layoutParams = expandLayout - .getLayoutParams(); - layoutParams.height = value; - expandLayout.setLayoutParams(layoutParams); - }); - return animator; - } - - - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index ee6a59061..e3d915ea3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -41,7 +41,6 @@ public class ModulesFragment extends Fragment { public static List listModules = new ArrayList<>(); public static List listModulesCache = new ArrayList<>(); - public static List listModulesDownload = new ArrayList<>(); private static final int FILE_SELECT_CODE = 0; private int viewPagePosition; private static final int RESULT_OK = 1; @@ -119,7 +118,6 @@ public class ModulesFragment extends Fragment { viewPagePosition = tabLayout.getSelectedTabPosition(); listModules.clear(); listModulesCache.clear(); - listModulesDownload.clear(); progressBar.setVisibility(View.VISIBLE); viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); @@ -155,14 +153,6 @@ public class ModulesFragment extends Fragment { } - public static class DownloadModuleFragment extends BaseRepoFragment { - - @Override - protected List listRepos() { - return listModulesDownload; - } - - } private class updateUI extends AsyncTask { @@ -186,7 +176,7 @@ public class ModulesFragment extends Fragment { private class TabsAdapter extends FragmentPagerAdapter { String[] tabTitles = new String[]{ - getString(R.string.modules), getString(R.string.cache_modules), "Download" + getString(R.string.modules), getString(R.string.cache_modules) }; public TabsAdapter(FragmentManager fm) { @@ -207,10 +197,8 @@ public class ModulesFragment extends Fragment { public Fragment getItem(int position) { if (position == 0) { return new NormalModuleFragment(); - } else if (position == 1) { - return new CacheModuleFragment(); } else { - return new DownloadModuleFragment(); + return new CacheModuleFragment(); } } } 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..a4e5535cd --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -0,0 +1,263 @@ +package com.topjohnwu.magisk; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.preference.PreferenceManager; +import android.support.v7.widget.RecyclerView; +import android.text.util.Linkify; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.topjohnwu.magisk.module.Repo; +import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.WebWindow; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class ReposAdapter extends RecyclerView.Adapter { + + private ReposFragment reposFragment; + private final List mList; + List mExpandedList; + @BindView(R.id.update) + ImageView updateImage; + @BindView(R.id.installed) + ImageView installedImage; + @BindView(R.id.expand_layout) + LinearLayout expandedLayout; + private View viewMain; + private Context context; + private boolean mIsInstalled, mCanUpdate; + private Repo repo; + private ViewHolder mHolder; + + public ReposAdapter(ReposFragment reposFragment, List list) { + this.reposFragment = reposFragment; + this.mList = list; + Log.d("Magisk", "ReposAdapter: I am alive. I have a list " + list.size()); + mExpandedList = new ArrayList<>(mList.size()); + for (int i = 0; i < mList.size(); i++) { + mExpandedList.add(false); + } + + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + viewMain = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_repo, parent, false); + ButterKnife.bind(this, viewMain); + context = parent.getContext(); + return new ViewHolder(viewMain); + } + +// @Override +// public boolean onOptionsItemSelected(MenuItem item) { +// switch (item.getItemId()) { +// case R.id.force_reload: +// listModulesDownload.clear(); +// new Utils.LoadModules(getActivity(), true).execute(); +// break; +// } +// +// return super.onOptionsItemSelected(item); +// } + + @Override + public void onBindViewHolder(final ViewHolder holder, int position) { + repo = mList.get(position); + mHolder = holder; + mExpandedList = new ArrayList<>(mList.size()); + for (int i = 0; i < mList.size(); i++) { + mExpandedList.add(false); + } + SetupViewElements(); + + } + + private void SetupViewElements() { + int mPosition = mHolder.getAdapterPosition(); + if (repo.getId() != null) { + mHolder.title.setText(repo.getName()); + mHolder.versionName.setText(repo.getmVersion()); + mHolder.description.setText(repo.getDescription()); + String authorString = this.context.getResources().getString(R.string.author) + " " + repo.getmAuthor(); + mHolder.author.setText(authorString); + if ((repo.getmLogUrl() != null) && (repo.getmLogUrl().equals(""))) { + mHolder.log.setText(repo.getmLogUrl()); + Linkify.addLinks(mHolder.log, Linkify.WEB_URLS); + } else { + mHolder.log.setVisibility(View.GONE); + } + mHolder.installedStatus.setText(repo.isInstalled() ? this.context.getResources().getString(R.string.module_installed) : this.context.getResources().getString(R.string.module_not_installed)); + if (mExpandedList.get(mPosition)) { + mHolder.expandLayout.setVisibility(View.VISIBLE); + } else { + mHolder.expandLayout.setVisibility(View.GONE); + } + if (repo.isInstalled()) { + mHolder.installedStatus.setTextColor(Color.parseColor("#14AD00")); + mHolder.updateStatus.setText(repo.canUpdate() ? this.context.getResources().getString(R.string.module_update_available) : this.context.getResources().getString(R.string.module_up_to_date)); + } + Log.d("Magisk", "ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + updateImage.setImageResource(R.drawable.ic_system_update_alt_black); + mCanUpdate = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); + + View.OnClickListener oCl = view -> { + if (view == updateImage) { + if (!mIsInstalled | mCanUpdate) { + + Utils.DownloadReceiver receiver = new Utils.DownloadReceiver() { + @Override + public void task(File file) { + Log.d("Magisk", "Task firing"); + new Utils.FlashZIP(context, repo.getId(), file.toString()).execute(); + } + }; + String filename = repo.getId().replace(" ", "") + ".zip"; + Utils.downloadAndReceive(context, receiver, repo.getmZipUrl(), filename); + } else { + Toast.makeText(context, repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); + } + } else if (view == mHolder.log) { + new WebWindow("Changelog", repo.getmLogUrl(), this.context); + } + }; + + updateImage.setOnClickListener(oCl); + mHolder.log.setOnClickListener(oCl); + if (prefs.contains("repo-isInstalled_" + repo.getId())) { + mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); + + } + + } + } + +// protected List mListRepos() { +// return ReposFragment.listModulesDownload; +// } + + @Override + public int getItemCount() { + return mList.size(); + } + + class ViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.title) + TextView title; + @BindView(R.id.version_name) + TextView versionName; + @BindView(R.id.description) + TextView description; + @BindView(R.id.author) + TextView author; + @BindView(R.id.log) + TextView log; + @BindView(R.id.installedStatus) + TextView installedStatus; + @BindView(R.id.updateStatus) + TextView updateStatus; + @BindView(R.id.expand_layout) + LinearLayout expandLayout; + private ValueAnimator mAnimator; + + public ViewHolder(View itemView) { + super(itemView); + WindowManager windowmanager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + ButterKnife.bind(this, itemView); + DisplayMetrics dimension = new DisplayMetrics(); + windowmanager.getDefaultDisplay().getMetrics(dimension); + expandLayout.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + + @Override + public boolean onPreDraw() { + final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); + expandLayout.setVisibility(View.GONE); + expandLayout.measure(widthSpec, heightSpec); + mAnimator = slideAnimator(0, expandLayout.getMeasuredHeight()); + return true; + } + + }); + + viewMain.setOnClickListener(view -> { + int position = getAdapterPosition(); + if (mExpandedList.get(position)) { + collapse(expandLayout); + } else { + expand(expandLayout); + } + mExpandedList.set(position, !mExpandedList.get(position)); + + }); + + } + + private void expand(View view) { + view.setVisibility(View.VISIBLE); + mAnimator.start(); + } + + private void collapse(View view) { + int finalHeight = view.getHeight(); + ValueAnimator mAnimator = slideAnimator(finalHeight, 0); + mAnimator.addListener(new Animator.AnimatorListener() { + + @Override + public void onAnimationEnd(Animator animator) { + view.setVisibility(View.GONE); + } + + @Override + public void onAnimationStart(Animator animator) { + } + + @Override + public void onAnimationCancel(Animator animator) { + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + }); + mAnimator.start(); + } + + private ValueAnimator slideAnimator(int start, int end) { + + ValueAnimator animator = ValueAnimator.ofInt(start, end); + + animator.addUpdateListener(valueAnimator -> { + int value = (Integer) valueAnimator.getAnimatedValue(); + ViewGroup.LayoutParams layoutParams = expandLayout + .getLayoutParams(); + layoutParams.height = value; + expandLayout.setLayoutParams(layoutParams); + }); + return animator; + } + + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java new file mode 100644 index 000000000..b8ae26934 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -0,0 +1,118 @@ +package com.topjohnwu.magisk; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +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.TextView; + +import com.topjohnwu.magisk.module.Repo; +import com.topjohnwu.magisk.module.RepoHelper; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class ReposFragment extends Fragment { + + public static List mListRepos = new ArrayList<>(); + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + @BindView(R.id.empty_rv) + TextView emptyTv; + @BindView(R.id.swipeRefreshLayout) + SwipeRefreshLayout swipeRefreshLayout; + private RepoHelper.TaskDelegate taskDelegate; + + @Nullable + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.single_repo_fragment, container, false); + ButterKnife.bind(this, view); + swipeRefreshLayout.setOnRefreshListener(() -> { + Log.d("Magisk","ReposFragment: WTF IM CALLED"); + this.LoadRepo(true); + }); + LoadRepo(false); + setHasOptionsMenu(false); + + if (mListRepos.size() == 0) { + emptyTv.setVisibility(View.VISIBLE); + recyclerView.setVisibility(View.GONE); + return view; + } + Log.d("Magisk", "ReposFragment: ListRepos size is " + listRepos().size()); + recyclerView.setAdapter(new ReposAdapter(this, mListRepos)); + return view; + } + + private void LoadRepo (boolean doReload) { + taskDelegate = result -> { + if (result.equals("Complete")) { + Log.d("Magisk", "ReposFragment, got delegate"); + UpdateUI(); + } + + + }; + Log.d("Magisk","ReposFragment, LoadRepo called"); + mListRepos.clear(); + RepoHelper mr = new RepoHelper(); + List magiskRepos = mr.listRepos(getActivity(), doReload,taskDelegate); + + for (Repo repo : magiskRepos) { + Log.d("Magisk", "ReposFragment: Adding repo from string " + repo.getId()); + mListRepos.add(repo); + } + + } + + + + @Override + public void onResume() { + super.onResume(); + LoadRepo(false); + + } + + + + protected List listRepos() { + return mListRepos; + } + + private void UpdateUI() { + Log.d("Magisk","ReposFragment: UpdateUI Called, size is " + listRepos().size()); + + if (listRepos().size() == 0) { + emptyTv.setVisibility(View.VISIBLE); + recyclerView.setVisibility(View.GONE); + + } + Log.d("Magisk", "ReposFragment: ListRepos size is " + listRepos().size()); + recyclerView.setAdapter(new ReposAdapter(this, listRepos())); + if (swipeRefreshLayout.isRefreshing()) { + swipeRefreshLayout.setRefreshing(false); + } + + + } + + + + + + + +} diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java index 715c25797..d2902db11 100644 --- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java @@ -23,6 +23,7 @@ import android.support.v7.widget.Toolbar; import android.view.MenuItem; import android.view.View; +import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.utils.Utils; import butterknife.BindView; @@ -60,14 +61,21 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView new Utils.Initialize(this).execute(); new Utils.CheckUpdates(this).execute(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + RepoHelper.TaskDelegate delegate = result -> { + //Do a thing here when we get a result we want + }; if (!prefs.contains("oauth_key")) { } if (!prefs.contains("hasCachedRepos")) { new Utils.LoadModules(this, true).execute(); + new Utils.LoadRepos(this, true,delegate).execute(); + } else { new Utils.LoadModules(getApplication(),false).execute(); - } + new Utils.LoadRepos(this, false,delegate).execute(); + + } setSupportActionBar(toolbar); @@ -146,6 +154,11 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView tag = "modules"; navFragment = new ModulesFragment(); break; + case R.id.downloads: + setTitle(R.string.downloads); + tag = "downloads"; + navFragment = new ReposFragment(); + break; case R.id.log: setTitle(R.string.log); tag = "log"; diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index 4d6d81881..2eae521d8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -66,7 +66,6 @@ public class Repo { WebRequest webreq = new WebRequest(); // Construct initial url for contents - Log.d("Magisk", "Repo: Fetch called, Manifest string is: " + mBaseUrl + "/contents?access_token=" + Utils.procFile(appContext.getString(R.string.some_string),appContext)); String repoString = webreq.makeWebServiceCall(mBaseUrl + "/contents?access_token=" + Utils.procFile(appContext.getString(R.string.some_string),appContext), WebRequest.GET); try { JSONArray repoArray = new JSONArray(repoString); @@ -85,10 +84,8 @@ public class Repo { e.printStackTrace(); } - Log.d("Magisk", "Repo: Inner fetch: " + mManifestUrl + "?access_token=" + Utils.procFile(appContext.getString(R.string.some_string),appContext)); WebRequest propReq = new WebRequest(); String manifestString = propReq.makeWebServiceCall(mManifestUrl,WebRequest.GET,true); - Log.d("Magisk","Repo: parseprops called from fetch for string " + manifestString); if (ParseProps(manifestString)) { PutProps(manifestString); @@ -103,7 +100,6 @@ public class Repo { editor.putString("repo_" + mId, manifestString); editor.putBoolean("hasCachedRepos", true); editor.putString("updated_" + mId, this.lastUpdate); - Log.d("Magisk", "Storing Preferences: " + manifestString); editor.apply(); } private boolean ParseProps(String string) { diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java index 1a04c0363..25d342728 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java @@ -18,6 +18,7 @@ import org.json.JSONObject; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; @@ -35,21 +36,21 @@ public class RepoHelper { private SharedPreferences prefs; private boolean apiFail; - public List listRepos(Context context, boolean refresh) { + public List listRepos(Context context, boolean refresh, TaskDelegate delegate) { prefs = PreferenceManager.getDefaultSharedPreferences(context); activityContext = context; + TaskDelegate mDelegate = delegate; + + if (!prefs.contains("hasCachedRepos") | refresh) { Log.d(TAG, "RepoHelper: Building from web"); - new MyAsyncTask().execute(); + new MyAsyncTask(delegate).execute(); List out = null; } else { Log.d(TAG, "RepoHelper: Building from cache"); BuildFromCache(); - - } - return repos; } @@ -58,7 +59,6 @@ public class RepoHelper { Map map = prefs.getAll(); for (Map.Entry entry : map.entrySet()) { if (entry.getKey().contains("repo_")) { - Log.d("Magisk", "RepoHelper: found entry for repo " + entry.getKey()); String repoString = entry.getValue().toString().replace(""", "\""); String[] repoStrings = repoString.split("\n"); for (String string : repoStrings) { @@ -73,26 +73,27 @@ public class RepoHelper { default: break; } - } - Log.d("Magisk", "RepoHelper: adding repo with id of " + mId); repos.add(new Repo(repoString, activityContext)); - - } - } } class MyAsyncTask extends AsyncTask { + private TaskDelegate delegate; + public MyAsyncTask(TaskDelegate delegate) { + this.delegate = delegate; + } @Override protected void onPreExecute() { super.onPreExecute(); } + + @Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); @@ -109,7 +110,6 @@ public class RepoHelper { // Making a request to url and getting response String token = activityContext.getString(R.string.some_string); String jsonStr = webreq.makeWebServiceCall(url + Utils.procFile(token, activityContext), WebRequest.GET); - Log.d("Magisk", "doInBackground Running, String: " + jsonStr + " Url: " + url); if (jsonStr != null && !jsonStr.isEmpty()) { try { @@ -136,7 +136,6 @@ public class RepoHelper { String[] valueSub = valueString.split("="); if (valueSub[0].equals("id")) { mId = valueSub[1]; - Log.d("Magisk", "RepoHelper: Got id for package of " + mId); if (prefs.contains("updated_" + mId)) { cacheUpdate = prefs.getString("updated_" + mId, ""); hasCachedDate = true; @@ -190,15 +189,22 @@ public class RepoHelper { if (apiFail) { Toast.makeText(activityContext, "GitHub API Limit reached, please try refreshing again in an hour.", Toast.LENGTH_LONG).show(); } else { + Log.d("Magisk","RepoHelper: postExecute fired"); + delegate.taskCompletionResult("Complete"); BuildFromCache(); + } - } // protected void onPostExecute(Void v) - } //class MyAsyncTask extends AsyncTask - + } + } protected void onPreExecute() { } + public interface TaskDelegate { + public void taskCompletionResult(String result); + } + + } 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 4a65fc4b2..a98f26635 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -23,9 +23,10 @@ import android.widget.Toast; import com.topjohnwu.magisk.ModulesFragment; import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.ReposFragment; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.module.Repo; +import com.topjohnwu.magisk.module.RepoHelper; import org.json.JSONException; import org.json.JSONObject; @@ -54,18 +55,17 @@ public class Utils { public static int magiskVersion, remoteMagiskVersion = -1, remoteAppVersion = -1; public static String magiskLink, magiskChangelog, appChangelog, appLink, phhLink, supersuLink; - private Context appContext; private static final String TAG = "Magisk"; 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"); - if (!Boolean.parseBoolean(ret.get(0)) && Shell.rootAccess()) ret = Shell.su("if [ -f " + path + " ]; then echo true; else echo false; fi"); + if (!Boolean.parseBoolean(ret.get(0)) && Shell.rootAccess()) + ret = Shell.su("if [ -f " + path + " ]; then echo true; else echo false; fi"); return Boolean.parseBoolean(ret.get(0)); } @@ -102,7 +102,7 @@ public class Utils { } public Utils(Context context) { - appContext = context; + Context appContext = context; } public static void downloadAndReceive(Context context, DownloadReceiver receiver, String link, String file) { @@ -128,15 +128,19 @@ public class Utils { long downloadID; public String mName; - public DownloadReceiver() {} - public DownloadReceiver(String name) { mName = name; } + 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)){ + if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { DownloadManager.Query query = new DownloadManager.Query(); query.setFilterById(downloadID); Cursor c = downloadManager.query(query); @@ -157,11 +161,14 @@ public class Utils { } } - public void setDownloadID(long id) { downloadID = id;} + public void setDownloadID(long id) { + downloadID = id; + } + public abstract void task(File file); } - public static class Initialize extends AsyncTask { + public static class Initialize extends AsyncTask { private Context mContext; @@ -199,7 +206,7 @@ public class Utils { 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(); + Snackbar.make(((Activity) mContext).findViewById(android.R.id.content), R.string.no_root_access, Snackbar.LENGTH_LONG).show(); } } @@ -318,8 +325,7 @@ public class Utils { 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) - { + switch (root) { case 0: downloadAndReceive( mContext, @@ -430,24 +436,45 @@ public class Utils { protected Void doInBackground(Void... voids) { ModulesFragment.listModules.clear(); ModulesFragment.listModulesCache.clear(); - ModulesFragment.listModulesDownload.clear(); List magisk = getModList(MAGISK_PATH); - Log.d("Magisk", "Utils: Reload called, loading modules from" + (doReload ? " the internet " : " cache")); + Log.d("Magisk", "Utils: Reload called, loading modules from" + (doReload ? " the internet " : " cache")); List magiskCache = getModList(MAGISK_CACHE_PATH); RepoHelper mr = new RepoHelper(); - List magiskRepos = mr.listRepos(mContext, doReload); for (String mod : magisk) { - Log.d("Magisk","Utils: Adding module from string " + mod); - ModulesFragment.listModules.add(new Module(mod,mContext)); + Log.d("Magisk", "Utils: Adding module from string " + mod); + ModulesFragment.listModules.add(new Module(mod, mContext)); } for (String mod : magiskCache) { - Log.d("Magisk","Utils: Adding cache module from string " + mod); - ModulesFragment.listModulesCache.add(new Module(mod,mContext)); + Log.d("Magisk", "Utils: Adding cache module from string " + mod); + ModulesFragment.listModulesCache.add(new Module(mod, mContext)); } + + return null; + } + } + + public static class LoadRepos extends AsyncTask { + + private Context mContext; + private boolean doReload; + private RepoHelper.TaskDelegate mTaskDelegate; + + public LoadRepos(Context context, boolean reload, RepoHelper.TaskDelegate delegate) { + mContext = context; + doReload = reload; + mTaskDelegate = delegate; + } + + @Override + protected Void doInBackground(Void... voids) { + ReposFragment.mListRepos.clear(); + RepoHelper mr = new RepoHelper(); + List magiskRepos = mr.listRepos(mContext, doReload, mTaskDelegate); + for (Repo repo : magiskRepos) { - Log.d("Magisk","Utils: Adding repo from string " + repo.getId()); - ModulesFragment.listModulesDownload.add(repo); + Log.d("Magisk", "Utils: Adding repo from string " + repo.getId()); + ReposFragment.mListRepos.add(repo); } return null; @@ -486,7 +513,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" ); - return Boolean.parseBoolean(ret.get(ret.size() -1)); + return Boolean.parseBoolean(ret.get(ret.size() - 1)); } } diff --git a/app/src/main/res/layout/single_repo_fragment.xml b/app/src/main/res/layout/single_repo_fragment.xml new file mode 100644 index 000000000..173657d94 --- /dev/null +++ b/app/src/main/res/layout/single_repo_fragment.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/drawer.xml b/app/src/main/res/menu/drawer.xml index 398f8b49b..eca988545 100644 --- a/app/src/main/res/menu/drawer.xml +++ b/app/src/main/res/menu/drawer.xml @@ -20,6 +20,11 @@ android:icon="@drawable/ic_extension" android:title="@string/modules"/> + + It seems that you have incompatible root installed\nDo you want to install Magisk compatible root now? MagiskRox666 GTYybRBTYf5his9kQ16ZNO7qgkBJ/5MyVe4CGceAOIoXgSnnk8FTd4F1dE9p5Eus + Downloads From 204e940dcbf6b48c581425f427744990b50f2fb8 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Sun, 11 Sep 2016 22:44:24 -0500 Subject: [PATCH 14/27] More work on "downloads" fragment Need to clean up animations yet, add "last update" label, etc. --- .../com/topjohnwu/magisk/ReposAdapter.java | 58 ++++---- app/src/main/res/drawable/ic_author.xml | 5 + app/src/main/res/drawable/ic_changelog.xml | 4 + .../res/drawable/ic_file_download_black.xml | 9 ++ app/src/main/res/drawable/ic_support.xml | 4 + app/src/main/res/layout/list_item_repo.xml | 131 +++++++++++------- .../res/layout/list_item_repo_expanded.xml | 67 --------- app/src/main/res/menu/drawer.xml | 2 +- 8 files changed, 138 insertions(+), 142 deletions(-) create mode 100644 app/src/main/res/drawable/ic_author.xml create mode 100644 app/src/main/res/drawable/ic_changelog.xml create mode 100644 app/src/main/res/drawable/ic_file_download_black.xml create mode 100644 app/src/main/res/drawable/ic_support.xml delete mode 100644 app/src/main/res/layout/list_item_repo_expanded.xml diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java index a4e5535cd..245425445 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -1,6 +1,8 @@ package com.topjohnwu.magisk; import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.content.SharedPreferences; @@ -10,11 +12,15 @@ import android.support.v7.widget.RecyclerView; import android.text.util.Linkify; import android.util.DisplayMetrics; import android.util.Log; +import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowManager; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.view.animation.TranslateAnimation; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -36,12 +42,6 @@ public class ReposAdapter extends RecyclerView.Adapter private ReposFragment reposFragment; private final List mList; List mExpandedList; - @BindView(R.id.update) - ImageView updateImage; - @BindView(R.id.installed) - ImageView installedImage; - @BindView(R.id.expand_layout) - LinearLayout expandedLayout; private View viewMain; private Context context; private boolean mIsInstalled, mCanUpdate; @@ -99,12 +99,6 @@ public class ReposAdapter extends RecyclerView.Adapter mHolder.description.setText(repo.getDescription()); String authorString = this.context.getResources().getString(R.string.author) + " " + repo.getmAuthor(); mHolder.author.setText(authorString); - if ((repo.getmLogUrl() != null) && (repo.getmLogUrl().equals(""))) { - mHolder.log.setText(repo.getmLogUrl()); - Linkify.addLinks(mHolder.log, Linkify.WEB_URLS); - } else { - mHolder.log.setVisibility(View.GONE); - } mHolder.installedStatus.setText(repo.isInstalled() ? this.context.getResources().getString(R.string.module_installed) : this.context.getResources().getString(R.string.module_not_installed)); if (mExpandedList.get(mPosition)) { mHolder.expandLayout.setVisibility(View.VISIBLE); @@ -115,13 +109,15 @@ public class ReposAdapter extends RecyclerView.Adapter mHolder.installedStatus.setTextColor(Color.parseColor("#14AD00")); mHolder.updateStatus.setText(repo.canUpdate() ? this.context.getResources().getString(R.string.module_update_available) : this.context.getResources().getString(R.string.module_up_to_date)); } + Log.d("Magisk", "ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - updateImage.setImageResource(R.drawable.ic_system_update_alt_black); + mHolder.updateImage.setImageResource(R.drawable.ic_file_download_black); mCanUpdate = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); View.OnClickListener oCl = view -> { - if (view == updateImage) { + Log.d("Magisk","Onlick captured, view is " + view.getId()); + if (view.getId() == mHolder.updateImage.getId()) { if (!mIsInstalled | mCanUpdate) { Utils.DownloadReceiver receiver = new Utils.DownloadReceiver() { @@ -136,13 +132,12 @@ public class ReposAdapter extends RecyclerView.Adapter } else { Toast.makeText(context, repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); } - } else if (view == mHolder.log) { - new WebWindow("Changelog", repo.getmLogUrl(), this.context); + } else if (view.getId() == mHolder.changeLog.getId()) { + new WebWindow("Changelog",repo.getmLogUrl(),this.context); } }; - - updateImage.setOnClickListener(oCl); - mHolder.log.setOnClickListener(oCl); + mHolder.changeLog.setOnClickListener(oCl); + mHolder.updateImage.setOnClickListener(oCl); if (prefs.contains("repo-isInstalled_" + repo.getId())) { mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); @@ -151,9 +146,6 @@ public class ReposAdapter extends RecyclerView.Adapter } } -// protected List mListRepos() { -// return ReposFragment.listModulesDownload; -// } @Override public int getItemCount() { @@ -170,15 +162,20 @@ public class ReposAdapter extends RecyclerView.Adapter TextView description; @BindView(R.id.author) TextView author; - @BindView(R.id.log) - TextView log; @BindView(R.id.installedStatus) TextView installedStatus; @BindView(R.id.updateStatus) TextView updateStatus; @BindView(R.id.expand_layout) LinearLayout expandLayout; + @BindView(R.id.update) + ImageView updateImage; + @BindView(R.id.installed) + ImageView installedImage; + @BindView(R.id.changeLog) + ImageView changeLog; private ValueAnimator mAnimator; + private AnimatorSet animSetUpRight, animSetDownLeft; public ViewHolder(View itemView) { super(itemView); @@ -197,6 +194,15 @@ public class ReposAdapter extends RecyclerView.Adapter expandLayout.setVisibility(View.GONE); expandLayout.measure(widthSpec, heightSpec); mAnimator = slideAnimator(0, expandLayout.getMeasuredHeight()); + ObjectAnimator animX2 = ObjectAnimator.ofFloat(mHolder.updateImage, "x", -45); + ObjectAnimator animY2 = ObjectAnimator.ofFloat(mHolder.updateImage, "y", -134); + animSetDownLeft = new AnimatorSet(); + animSetDownLeft.playTogether(animX2, animY2); + ObjectAnimator animX = ObjectAnimator.ofFloat(mHolder.updateImage, "x", 45); + ObjectAnimator animY = ObjectAnimator.ofFloat(mHolder.updateImage, "y", 134); + animSetUpRight = new AnimatorSet(); + animSetUpRight.playTogether(animX, animY); + animSetUpRight.start(); return true; } @@ -218,6 +224,8 @@ public class ReposAdapter extends RecyclerView.Adapter private void expand(View view) { view.setVisibility(View.VISIBLE); mAnimator.start(); + animSetDownLeft.start(); + } private void collapse(View view) { @@ -243,6 +251,8 @@ public class ReposAdapter extends RecyclerView.Adapter } }); mAnimator.start(); + animSetUpRight.start(); + } private ValueAnimator slideAnimator(int start, int end) { diff --git a/app/src/main/res/drawable/ic_author.xml b/app/src/main/res/drawable/ic_author.xml new file mode 100644 index 000000000..81cffc428 --- /dev/null +++ b/app/src/main/res/drawable/ic_author.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/ic_changelog.xml b/app/src/main/res/drawable/ic_changelog.xml new file mode 100644 index 000000000..f4b1dd42b --- /dev/null +++ b/app/src/main/res/drawable/ic_changelog.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_file_download_black.xml b/app/src/main/res/drawable/ic_file_download_black.xml new file mode 100644 index 000000000..d05655222 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_download_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_support.xml b/app/src/main/res/drawable/ic_support.xml new file mode 100644 index 000000000..6ab452192 --- /dev/null +++ b/app/src/main/res/drawable/ic_support.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/layout/list_item_repo.xml b/app/src/main/res/layout/list_item_repo.xml index bda43c4fc..696fce974 100644 --- a/app/src/main/res/layout/list_item_repo.xml +++ b/app/src/main/res/layout/list_item_repo.xml @@ -2,7 +2,6 @@ + + android:layout_height="match_parent" + android:orientation="vertical"> @@ -50,7 +50,7 @@ android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="@android:color/tertiary_text_dark" android:textIsSelectable="false" - android:textStyle="bold|italic" /> + android:textStyle="bold|italic"/> + - + + + + + + + + + + + + + + + + + + + + - - - - - - - - diff --git a/app/src/main/res/layout/list_item_repo_expanded.xml b/app/src/main/res/layout/list_item_repo_expanded.xml deleted file mode 100644 index c7303199a..000000000 --- a/app/src/main/res/layout/list_item_repo_expanded.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/menu/drawer.xml b/app/src/main/res/menu/drawer.xml index eca988545..39bb96407 100644 --- a/app/src/main/res/menu/drawer.xml +++ b/app/src/main/res/menu/drawer.xml @@ -22,7 +22,7 @@ Date: Mon, 12 Sep 2016 12:03:02 -0500 Subject: [PATCH 15/27] Clean up graphics and animations --- .../com/topjohnwu/magisk/ReposAdapter.java | 48 ++++++---- app/src/main/res/layout/list_item_repo.xml | 94 +++++++++++-------- 2 files changed, 83 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java index 245425445..b14d080c8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -117,6 +117,7 @@ public class ReposAdapter extends RecyclerView.Adapter View.OnClickListener oCl = view -> { Log.d("Magisk","Onlick captured, view is " + view.getId()); + if (view.getId() == mHolder.updateImage.getId()) { if (!mIsInstalled | mCanUpdate) { @@ -132,12 +133,18 @@ public class ReposAdapter extends RecyclerView.Adapter } else { Toast.makeText(context, repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); } - } else if (view.getId() == mHolder.changeLog.getId()) { + } if (view.getId() == mHolder.changeLog.getId()) { new WebWindow("Changelog",repo.getmLogUrl(),this.context); + } if (view.getId() == mHolder.authorLink.getId()) { + new WebWindow("Donate",repo.getmDonateUrl(),this.context); + } if (view.getId() == mHolder.supportLink.getId()) { + new WebWindow("Support",repo.getmSupportUrl(),this.context); } }; mHolder.changeLog.setOnClickListener(oCl); mHolder.updateImage.setOnClickListener(oCl); + mHolder.authorLink.setOnClickListener(oCl); + mHolder.supportLink.setOnClickListener(oCl); if (prefs.contains("repo-isInstalled_" + repo.getId())) { mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); @@ -174,8 +181,13 @@ public class ReposAdapter extends RecyclerView.Adapter ImageView installedImage; @BindView(R.id.changeLog) ImageView changeLog; + @BindView(R.id.authorLink) + ImageView authorLink; + @BindView(R.id.supportLink) + ImageView supportLink; private ValueAnimator mAnimator; - private AnimatorSet animSetUpRight, animSetDownLeft; + private ObjectAnimator animY2; + private ViewHolder holder; public ViewHolder(View itemView) { super(itemView); @@ -183,26 +195,22 @@ public class ReposAdapter extends RecyclerView.Adapter ButterKnife.bind(this, itemView); DisplayMetrics dimension = new DisplayMetrics(); windowmanager.getDefaultDisplay().getMetrics(dimension); - expandLayout.getViewTreeObserver().addOnPreDrawListener( + holder = this; + this.expandLayout.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); - expandLayout.setVisibility(View.GONE); - expandLayout.measure(widthSpec, heightSpec); - mAnimator = slideAnimator(0, expandLayout.getMeasuredHeight()); - ObjectAnimator animX2 = ObjectAnimator.ofFloat(mHolder.updateImage, "x", -45); - ObjectAnimator animY2 = ObjectAnimator.ofFloat(mHolder.updateImage, "y", -134); - animSetDownLeft = new AnimatorSet(); - animSetDownLeft.playTogether(animX2, animY2); - ObjectAnimator animX = ObjectAnimator.ofFloat(mHolder.updateImage, "x", 45); - ObjectAnimator animY = ObjectAnimator.ofFloat(mHolder.updateImage, "y", 134); - animSetUpRight = new AnimatorSet(); - animSetUpRight.playTogether(animX, animY); - animSetUpRight.start(); + holder.expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); + holder.expandLayout.setVisibility(View.GONE); + holder.expandLayout.measure(widthSpec, heightSpec); + final int holderHeight = holder.expandLayout.getMeasuredHeight(); + mAnimator = slideAnimator(0, holderHeight); + animY2 = ObjectAnimator.ofFloat(holder.updateImage, "translationY", holderHeight/2); + + return true; } @@ -211,9 +219,9 @@ public class ReposAdapter extends RecyclerView.Adapter viewMain.setOnClickListener(view -> { int position = getAdapterPosition(); if (mExpandedList.get(position)) { - collapse(expandLayout); + collapse(holder.expandLayout); } else { - expand(expandLayout); + expand(holder.expandLayout); } mExpandedList.set(position, !mExpandedList.get(position)); @@ -224,7 +232,7 @@ public class ReposAdapter extends RecyclerView.Adapter private void expand(View view) { view.setVisibility(View.VISIBLE); mAnimator.start(); - animSetDownLeft.start(); + animY2.start(); } @@ -251,7 +259,7 @@ public class ReposAdapter extends RecyclerView.Adapter } }); mAnimator.start(); - animSetUpRight.start(); + animY2.reverse(); } diff --git a/app/src/main/res/layout/list_item_repo.xml b/app/src/main/res/layout/list_item_repo.xml index 696fce974..7a863268d 100644 --- a/app/src/main/res/layout/list_item_repo.xml +++ b/app/src/main/res/layout/list_item_repo.xml @@ -19,29 +19,28 @@ android:layout_height="match_parent" android:orientation="vertical"> - - + > + android:textIsSelectable="false" + android:layout_alignParentStart="true" + android:layout_alignParentTop="true" + android:layout_marginTop="0dp" /> + android:textStyle="bold|italic" + android:layout_alignParentStart="true" + android:layout_below="@id/title" + /> + + + android:textIsSelectable="false" + android:layout_alignParentStart="true" + android:layout_below="@id/update" + /> + android:orientation="vertical" + android:layout_below="@id/description" + android:layout_alignParentStart="true" + + > + android:textIsSelectable="false" + android:layout_marginBottom="20dip" /> + android:orientation="horizontal" + android:layout_marginBottom="0dip"> - - - - - + - + + + From 1468dfd6b60ec6b32a52cd73b98a3d6ae13a52cf Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Mon, 12 Sep 2016 14:33:03 -0500 Subject: [PATCH 16/27] Add CacheModule display string to title --- app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java | 9 ++++++++- app/src/main/java/com/topjohnwu/magisk/module/Repo.java | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java index b14d080c8..2a1b78c0e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -93,8 +93,15 @@ public class ReposAdapter extends RecyclerView.Adapter private void SetupViewElements() { int mPosition = mHolder.getAdapterPosition(); + String titleString; if (repo.getId() != null) { - mHolder.title.setText(repo.getName()); + if (repo.isCacheModule()) { + titleString = "[Cache] " + repo.getName(); + } else { + titleString = repo.getName(); + } + + mHolder.title.setText(titleString); mHolder.versionName.setText(repo.getmVersion()); mHolder.description.setText(repo.getDescription()); String authorString = this.context.getResources().getString(R.string.author) + " " + repo.getmAuthor(); diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index 2eae521d8..1ef4a419b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -31,7 +31,7 @@ public class Repo { private String mDonateUrl; private String lastUpdate; private Context appContext; - private boolean mIsInstalled,mCanUpdate; + private boolean mIsInstalled,mCanUpdate,mIsCacheModule; public Repo(String manifestString, Context context) { @@ -133,6 +133,9 @@ public class Repo { case "donate": this.mDonateUrl = props[1]; break; + case "cacheModule": + this.mIsCacheModule = Boolean.valueOf(props[1]); + break; case "support": this.mSupportUrl = props[1]; break; @@ -261,5 +264,6 @@ public class Repo { public boolean isInstalled() { return mIsInstalled; } public boolean canUpdate() { return mCanUpdate; } + public boolean isCacheModule() { return mIsCacheModule; } } From 62dd8f35c06fa493bfec138ab9428269acf6a8ca Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Mon, 12 Sep 2016 14:40:15 -0500 Subject: [PATCH 17/27] Add custom comparator for Repos (sort them alphabetically) Now they come out in a nice alphabetized list... --- .../java/com/topjohnwu/magisk/module/RepoHelper.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java index 25d342728..fb66ef709 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java @@ -19,6 +19,8 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Map; @@ -51,6 +53,7 @@ public class RepoHelper { BuildFromCache(); } + Collections.sort(repos, new CustomComparator()); return repos; } @@ -205,6 +208,12 @@ public class RepoHelper { public void taskCompletionResult(String result); } + public class CustomComparator implements Comparator { + @Override + public int compare(Repo o1, Repo o2) { + return o1.getName().compareTo(o2.getName()); + } + } } From 3d4b4e04c5c3dfea87cca9a6aa308429ae39e7d4 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Mon, 12 Sep 2016 16:47:32 -0500 Subject: [PATCH 18/27] Bring module fragment up to same level as repo fragment --- .../topjohnwu/magisk/BaseModuleFragment.java | 45 +++- .../com/topjohnwu/magisk/ModulesFragment.java | 10 + .../com/topjohnwu/magisk/module/Module.java | 55 +++-- .../com/topjohnwu/magisk/utils/Utils.java | 9 +- app/src/main/res/layout/list_item_module.xml | 202 ++++++++++++------ app/src/main/res/layout/list_item_repo.xml | 3 +- app/src/main/res/values/strings.xml | 2 +- 7 files changed, 237 insertions(+), 89 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index c51e59f0a..2787f4f75 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -25,6 +25,7 @@ import android.widget.TextView; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.WebWindow; import java.util.ArrayList; import java.util.List; @@ -132,7 +133,36 @@ public abstract class BaseModuleFragment extends Fragment { holder.title.setText(module.getName()); holder.versionName.setText(module.getVersion()); holder.description.setText(module.getDescription()); + holder.author.setText(module.getAuthor()); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (prefs.contains("repo-canUpdate_" + module.getId())) { + if (prefs.getBoolean("repo-canUpdate_" + module.getId(),false)) { + holder.updateStatus.setText(R.string.module_update_available); + holder.updateStatus.setVisibility(View.VISIBLE); + } else { + holder.updateStatus.setVisibility(View.GONE); + } + } + + View.OnClickListener oCl = new View.OnClickListener() { + @Override + public void onClick(View view) { + if (view.getId() == holder.changeLog.getId()) { + new WebWindow("Changelog",module.getChangeLog(),context); + } + if (view.getId() == holder.authorLink.getId()) { + new WebWindow("Donate",module.getmDonateUrl(),context); + } + if (view.getId() == holder.supportLink.getId()) { + new WebWindow("Support",module.getmSupportUrl(),context); + } + } + }; + + holder.authorLink.setOnClickListener(oCl); + holder.changeLog.setOnClickListener(oCl); + holder.supportLink.setOnClickListener(oCl); holder.checkBox.setChecked(module.isEnabled()); holder.checkBox.setOnCheckedChangeListener((compoundButton, b) -> chboxListener.onItemClick(compoundButton, holder.getAdapterPosition())); @@ -170,14 +200,15 @@ public abstract class BaseModuleFragment extends Fragment { @BindView(R.id.version_name) TextView versionName; @BindView(R.id.description) TextView description; - @BindView(R.id.warning) TextView warning; - @BindView(R.id.checkbox) CheckBox checkBox; - @BindView(R.id.delete) - ImageView delete; - @BindView(R.id.expand_layout) - LinearLayout expandLayout; + @BindView(R.id.author) TextView author; + @BindView(R.id.updateStatus) TextView updateStatus; + @BindView(R.id.delete) ImageView delete; + @BindView(R.id.changeLog) ImageView changeLog; + @BindView(R.id.authorLink) ImageView authorLink; + @BindView(R.id.supportLink) ImageView supportLink; + @BindView(R.id.expand_layout) LinearLayout expandLayout; private ValueAnimator mAnimator; private int mMeasuredHeight; @@ -188,6 +219,7 @@ public abstract class BaseModuleFragment extends Fragment { DisplayMetrics dimension = new DisplayMetrics(); windowmanager.getDefaultDisplay().getMetrics(dimension); final int mHeight = dimension.heightPixels; + expandLayout.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @@ -195,7 +227,6 @@ public abstract class BaseModuleFragment extends Fragment { public boolean onPreDraw() { expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); expandLayout.setVisibility(View.GONE); - final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); final int heightSpec = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); expandLayout.measure(widthSpec, heightSpec); diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index e3d915ea3..c3f64ee6a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -31,6 +31,8 @@ import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.utils.Utils; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.regex.Pattern; @@ -123,6 +125,8 @@ public class ModulesFragment extends Fragment { tabLayout.setupWithViewPager(viewPager); viewPager.setCurrentItem(viewPagePosition); new Utils.LoadModules(getActivity(), true).execute(); + Collections.sort(listModules,new CustomComparator()); + Collections.sort(listModulesCache,new CustomComparator()); new updateUI().execute(); break; } @@ -202,5 +206,11 @@ public class ModulesFragment extends Fragment { } } } + public class CustomComparator implements Comparator { + @Override + public int compare(Module o1, Module o2) { + return o1.getName().compareTo(o2.getName()); + } + } } 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 43ebc3cc4..09dce957b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -15,8 +15,8 @@ public class Module { private String mName = null; private String mVersion = "(No version provided)"; private String mDescription = "(No description provided)"; - private String mUrl,mSupportUrl,mDonateUrl,mZipUrl,mBaseUrl,mManifestUrl,mAuthor; - private boolean mEnable, mRemove,mUpdateAvailable,mIsOnline; + private String mUrl,mSupportUrl,mDonateUrl,mZipUrl,mBaseUrl,mManifestUrl,mAuthor,mLogUrl; + private boolean mEnable, mRemove,mUpdateAvailable,mIsOnline,mIsCacheModule; private String mId; @@ -43,40 +43,46 @@ public class Module { this.mVersionCode = Integer.valueOf(props[1]); break; case "name": - this.mName = value; + this.mName = props[1]; break; case "author": - this.mAuthor = value; + this.mAuthor = props[1]; break; case "id": - this.mId = value; + this.mId = props[1]; break; case "version": - this.mVersion = value; + this.mVersion = props[1]; break; case "description": - this.mDescription = value; + this.mDescription = props[1]; break; case "donate": - this.mDonateUrl = value; + this.mDonateUrl = props[1]; + break; + case "cacheModule": + this.mIsCacheModule = Boolean.valueOf(props[1]); break; case "support": - this.mSupportUrl = value; + this.mSupportUrl = props[1]; break; case "donateUrl": - this.mDonateUrl = value; + this.mDonateUrl = props[1]; break; case "zipUrl": - this.mZipUrl = value; + this.mZipUrl = props[1]; break; case "baseUrl": - this.mBaseUrl = value; + this.mBaseUrl = props[1]; break; case "manifestUrl": - this.mManifestUrl = value; + this.mManifestUrl = props[1]; + break; + case "logUrl": + this.mLogUrl = props[1]; break; default: - Log.d("Magisk", "Module: Manifest string not recognized: " + props[0]); + Log.d("Magisk", "Manifest string not recognized: " + props[0]); break; } @@ -106,6 +112,7 @@ public class Module { mIsOnline = true; } else mIsOnline = false; } + if (idEntry[0].equals("versionCode")) { if (idEntry.length != 2) { continue; @@ -171,6 +178,14 @@ public class Module { return mVersion; } + public String getAuthor() { + return mAuthor; + } + + public String getId() {return mId; } + + public String getChangeLog() {return mLogUrl; } + public String getDescription() { return mDescription; } @@ -199,6 +214,18 @@ public class Module { return mRemove; } + public String getmDonateUrl() { + return mDonateUrl; + } + + public String getmManifestUrl() { + return mManifestUrl; + } + + public String getmSupportUrl() { + return mSupportUrl; + } + public boolean isOnline() {return mIsOnline; } public boolean isUpdateAvailable() { return mUpdateAvailable; } 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 a98f26635..52b74550f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -41,6 +41,8 @@ import java.net.URL; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import javax.crypto.BadPaddingException; @@ -439,12 +441,12 @@ public class Utils { List magisk = getModList(MAGISK_PATH); Log.d("Magisk", "Utils: Reload called, loading modules from" + (doReload ? " the internet " : " cache")); List magiskCache = getModList(MAGISK_CACHE_PATH); - RepoHelper mr = new RepoHelper(); for (String mod : magisk) { Log.d("Magisk", "Utils: Adding module from string " + mod); ModulesFragment.listModules.add(new Module(mod, mContext)); } + for (String mod : magiskCache) { Log.d("Magisk", "Utils: Adding cache module from string " + mod); ModulesFragment.listModulesCache.add(new Module(mod, mContext)); @@ -452,6 +454,7 @@ public class Utils { return null; } + } public static class LoadRepos extends AsyncTask { @@ -479,6 +482,8 @@ public class Utils { return null; } + + } public static class FlashZIP extends AsyncTask { @@ -544,4 +549,6 @@ public class Utils { void onItemClick(View view, int position); } + + } diff --git a/app/src/main/res/layout/list_item_module.xml b/app/src/main/res/layout/list_item_module.xml index 00ce343c2..72c6951d5 100644 --- a/app/src/main/res/layout/list_item_module.xml +++ b/app/src/main/res/layout/list_item_module.xml @@ -1,112 +1,184 @@ - + xmlns:card_view="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginBottom="3dip" + android:layout_marginLeft="8dip" + android:layout_marginRight="8dip" + android:layout_marginTop="3dip" + android:background="?android:attr/selectableItemBackground" + android:minHeight="?android:attr/listPreferredItemHeight" + card_view:cardCornerRadius="2dp" + card_view:cardElevation="2dp"> - + android:layout_gravity="center_vertical"> + android:textIsSelectable="false" /> - + + + + + + + + + + + + + + + + + + + + + + android:textIsSelectable="false" /> - + + + android:layout_alignParentStart="true" + android:layout_below="@id/description" + android:minHeight="100dp" + android:orientation="vertical" - - + > - - + - - + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_item_repo.xml b/app/src/main/res/layout/list_item_repo.xml index 7a863268d..39e09fae6 100644 --- a/app/src/main/res/layout/list_item_repo.xml +++ b/app/src/main/res/layout/list_item_repo.xml @@ -71,7 +71,7 @@ android:id="@+id/description" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" + android:layout_gravity="center_vertical" android:textAppearance="?android:attr/textAppearanceSmall" android:textIsSelectable="false" android:layout_alignParentStart="true" @@ -111,6 +111,7 @@ android:id="@+id/updateStatus" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" android:textAppearance="?android:attr/textAppearanceSmall" android:textIsSelectable="false" android:layout_marginBottom="20dip" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 631912cbd..1f072f42a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,7 +42,7 @@ Cache modules No modules found - An update is available + An update is available! Module is up-to-date Module is installed Module is not installed From e690f6d4871160564ce2c33a4e8d9a25dce56350 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Mon, 12 Sep 2016 16:57:06 -0500 Subject: [PATCH 19/27] Add some more strings from preferences... We have the knowledge...USE IT. --- .../java/com/topjohnwu/magisk/module/Module.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) 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 09dce957b..32034b1d2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -37,7 +37,6 @@ public class Module { continue; } - String value = props[1].trim(); switch (props[0]) { case "versionCode": this.mVersionCode = Integer.valueOf(props[1]); @@ -112,6 +111,18 @@ public class Module { mIsOnline = true; } else mIsOnline = false; } + if (idEntry[0].equals("logUrl")) { + mLogUrl = idEntry[1]; + } + if (idEntry[0].equals("support")) { + mSupportUrl = idEntry[1]; + } + if (idEntry[0].equals("zipUrl")) { + mZipUrl = idEntry[1]; + } + if (idEntry[0].equals("donate")) { + mDonateUrl = idEntry[1]; + } if (idEntry[0].equals("versionCode")) { if (idEntry.length != 2) { From b3ba79a3baa7dea9230529e4fd84005aaae831ad Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Mon, 12 Sep 2016 23:05:04 -0500 Subject: [PATCH 20/27] Add Swipe-to-refresh for Modules, Code Cleanup, Stylizations Moar updates. Modules now swipe to refresh and indicate properly-ish. Cleanup minor code stuff. Colorize icons to match, set global color variable so it can be changed... --- .../com/topjohnwu/magisk/AboutActivity.java | 2 +- .../topjohnwu/magisk/BaseModuleFragment.java | 30 ++++++---- .../com/topjohnwu/magisk/ReposAdapter.java | 28 ++++----- .../com/topjohnwu/magisk/ReposFragment.java | 6 +- .../com/topjohnwu/magisk/module/Repo.java | 20 ++++--- .../topjohnwu/magisk/module/RepoHelper.java | 57 ++++++------------- app/src/main/res/layout/list_item_module.xml | 15 ++--- app/src/main/res/layout/list_item_repo.xml | 19 +++---- .../res/layout/single_module_fragment.xml | 15 ++--- app/src/main/res/values/colors.xml | 2 +- app/src/main/res/values/strings.xml | 1 + 11 files changed, 86 insertions(+), 109 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java index 59542e177..c384fe855 100644 --- a/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java @@ -24,7 +24,7 @@ import java.io.InputStream; import butterknife.BindView; import butterknife.ButterKnife; -public class AboutActivity extends AppCompatActivity { +public class AboutActivity extends AppCompatActivity { private static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/MagiskManager"; private static final String XDA_THREAD = "http://forum.xda-developers.com/android/software/mod-magisk-v1-universal-systemless-t3432382"; diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index 2787f4f75..829008885 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -9,6 +9,7 @@ import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.util.DisplayMetrics; import android.util.Log; @@ -23,6 +24,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import com.topjohnwu.magisk.module.Module; +import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebWindow; @@ -34,13 +36,18 @@ import butterknife.BindView; import butterknife.ButterKnife; public abstract class BaseModuleFragment extends Fragment { - + @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; @BindView(R.id.recyclerView) RecyclerView recyclerView; @BindView(R.id.empty_rv) TextView emptyTv; - + private RepoHelper.TaskDelegate mDelegate; private SharedPreferences prefs; + public BaseModuleFragment SetDelegate(RepoHelper.TaskDelegate delegate) { + mDelegate = delegate; + return null; + } + @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -48,15 +55,18 @@ public abstract class BaseModuleFragment extends Fragment { ButterKnife.bind(this, viewMain); - prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); - prefs.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() { - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { - if (s.contains("updated")) { - viewMain.invalidate(); - viewMain.requestLayout(); + mSwipeRefreshLayout.setOnRefreshListener(() -> { + Log.d("Magisk","ModulesFragment: SWIPE"); + mDelegate.taskCompletionResult("OK"); + }); + + + prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + prefs.registerOnSharedPreferenceChangeListener((sharedPreferences, s) -> { + if (s.contains("updated")) { + viewMain.invalidate(); + viewMain.requestLayout(); - } } }); if (listModules().size() == 0) { diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java index 2a1b78c0e..9adb8bbb4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -1,7 +1,6 @@ package com.topjohnwu.magisk; import android.animation.Animator; -import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; @@ -9,18 +8,13 @@ import android.content.SharedPreferences; import android.graphics.Color; import android.preference.PreferenceManager; import android.support.v7.widget.RecyclerView; -import android.text.util.Linkify; import android.util.DisplayMetrics; import android.util.Log; -import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowManager; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.view.animation.TranslateAnimation; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -119,11 +113,10 @@ public class ReposAdapter extends RecyclerView.Adapter Log.d("Magisk", "ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - mHolder.updateImage.setImageResource(R.drawable.ic_file_download_black); mCanUpdate = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); View.OnClickListener oCl = view -> { - Log.d("Magisk","Onlick captured, view is " + view.getId()); + Log.d("Magisk", "Onlick captured, view is " + view.getId()); if (view.getId() == mHolder.updateImage.getId()) { if (!mIsInstalled | mCanUpdate) { @@ -140,12 +133,15 @@ public class ReposAdapter extends RecyclerView.Adapter } else { Toast.makeText(context, repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); } - } if (view.getId() == mHolder.changeLog.getId()) { - new WebWindow("Changelog",repo.getmLogUrl(),this.context); - } if (view.getId() == mHolder.authorLink.getId()) { - new WebWindow("Donate",repo.getmDonateUrl(),this.context); - } if (view.getId() == mHolder.supportLink.getId()) { - new WebWindow("Support",repo.getmSupportUrl(),this.context); + } + if (view.getId() == mHolder.changeLog.getId()) { + new WebWindow("Changelog", repo.getmLogText(), this.context); + } + if (view.getId() == mHolder.authorLink.getId()) { + new WebWindow("Donate", repo.getmDonateUrl(), this.context); + } + if (view.getId() == mHolder.supportLink.getId()) { + new WebWindow("Support", repo.getmSupportUrl(), this.context); } }; mHolder.changeLog.setOnClickListener(oCl); @@ -160,7 +156,6 @@ public class ReposAdapter extends RecyclerView.Adapter } } - @Override public int getItemCount() { return mList.size(); @@ -215,8 +210,7 @@ public class ReposAdapter extends RecyclerView.Adapter holder.expandLayout.measure(widthSpec, heightSpec); final int holderHeight = holder.expandLayout.getMeasuredHeight(); mAnimator = slideAnimator(0, holderHeight); - animY2 = ObjectAnimator.ofFloat(holder.updateImage, "translationY", holderHeight/2); - + animY2 = ObjectAnimator.ofFloat(holder.updateImage, "translationY", holderHeight / 2); return true; } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java index b8ae26934..72e0300c2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -31,7 +31,6 @@ public class ReposFragment extends Fragment { TextView emptyTv; @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout; - private RepoHelper.TaskDelegate taskDelegate; @Nullable @@ -57,18 +56,17 @@ public class ReposFragment extends Fragment { } private void LoadRepo (boolean doReload) { - taskDelegate = result -> { + RepoHelper.TaskDelegate taskDelegate = result -> { if (result.equals("Complete")) { Log.d("Magisk", "ReposFragment, got delegate"); UpdateUI(); } - }; Log.d("Magisk","ReposFragment, LoadRepo called"); mListRepos.clear(); RepoHelper mr = new RepoHelper(); - List magiskRepos = mr.listRepos(getActivity(), doReload,taskDelegate); + List magiskRepos = mr.listRepos(getActivity(), doReload, taskDelegate); for (Repo repo : magiskRepos) { Log.d("Magisk", "ReposFragment: Adding repo from string " + repo.getId()); diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index 1ef4a419b..948d92f70 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -18,7 +18,7 @@ import java.util.Date; public class Repo { private String mBaseUrl; private String mZipUrl; - private String mLogUrl; + private String mLogText; private String mManifestUrl; private String mVersion; private String mName; @@ -77,7 +77,9 @@ public class Repo { } else if (name.equals("module.prop")) { this.mManifestUrl = jsonobject.getString("download_url"); } else if (name.equals("changelog.txt")) { - this.mLogUrl = jsonobject.getString("download_url"); + String logUrl = jsonobject.getString("download_url");; + String logText = webreq.makeWebServiceCall(logUrl,WebRequest.GET); + this.mLogText = logText; } } } catch (JSONException e) { @@ -94,9 +96,10 @@ public class Repo { } private void PutProps(String manifestString) { - manifestString = manifestString + "zipUrl=" + mZipUrl + "\nbaseUrl=" + mBaseUrl + "\nlogUrl=" + mLogUrl + "\nmanifestUrl=" + mManifestUrl; + manifestString = manifestString + "zipUrl=" + mZipUrl + "\nbaseUrl=" + mBaseUrl + "\nmanifestUrl=" + mManifestUrl; SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext); SharedPreferences.Editor editor = prefs.edit(); + editor.putString("log_" + mId, mLogText); editor.putString("repo_" + mId, manifestString); editor.putBoolean("hasCachedRepos", true); editor.putString("updated_" + mId, this.lastUpdate); @@ -151,9 +154,6 @@ public class Repo { case "manifestUrl": this.mManifestUrl = props[1]; break; - case "logUrl": - this.mLogUrl = props[1]; - break; default: Log.d("Magisk", "Manifest string not recognized: " + props[0]); break; @@ -171,7 +171,9 @@ public class Repo { if (prefs.contains("updated_" + this.mId)) { lastUpdate = prefs.getString("updated_" + this.mId,""); } - + if (prefs.contains("log_" + this.mId)) { + mLogText = prefs.getString("log_" + this.mId,""); + } return this.mId != null; @@ -237,8 +239,8 @@ public class Repo { return mBaseUrl; } - public String getmLogUrl() { - return mLogUrl; + public String getmLogText() { + return mLogText; } diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java index fb66ef709..61a534b45 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java @@ -18,36 +18,31 @@ import org.json.JSONObject; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.Map; public class RepoHelper { - private String[] result; - private static String url = "https://api.github.com/orgs/Magisk-Modules-Repo/repos?access_token="; - private static List repos = new ArrayList(); - private static final String TAG_ID = "id"; - private static final String TAG_NAME = "name"; + private static List repos = new ArrayList<>(); private static String TAG = "Magisk"; - private String mName, mId, mUrl; private Context activityContext; - private Date updatedDate, currentDate; + private Date updatedDate; private SharedPreferences prefs; private boolean apiFail; + public RepoHelper() { + } + public List listRepos(Context context, boolean refresh, TaskDelegate delegate) { prefs = PreferenceManager.getDefaultSharedPreferences(context); activityContext = context; - TaskDelegate mDelegate = delegate; - if (!prefs.contains("hasCachedRepos") | refresh) { Log.d(TAG, "RepoHelper: Building from web"); - new MyAsyncTask(delegate).execute(); - List out = null; + new BuildFromWeb(delegate).execute(); } else { Log.d(TAG, "RepoHelper: Building from cache"); BuildFromCache(); @@ -63,40 +58,25 @@ public class RepoHelper { for (Map.Entry entry : map.entrySet()) { if (entry.getKey().contains("repo_")) { String repoString = entry.getValue().toString().replace(""", "\""); - String[] repoStrings = repoString.split("\n"); - for (String string : repoStrings) { - String[] splitStrings = string.split("="); - switch (splitStrings[0]) { - case ("id"): - mId = splitStrings[1]; - break; - case ("baseUrl"): - mUrl = splitStrings[1]; - break; - default: - break; - } - } repos.add(new Repo(repoString, activityContext)); } } } - - class MyAsyncTask extends AsyncTask { + class BuildFromWeb extends AsyncTask { private TaskDelegate delegate; - public MyAsyncTask(TaskDelegate delegate) { + + public BuildFromWeb(TaskDelegate delegate) { this.delegate = delegate; } + @Override protected void onPreExecute() { super.onPreExecute(); } - - @Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); @@ -112,7 +92,8 @@ public class RepoHelper { // Making a request to url and getting response String token = activityContext.getString(R.string.some_string); - String jsonStr = webreq.makeWebServiceCall(url + Utils.procFile(token, activityContext), WebRequest.GET); + String url1 = activityContext.getString(R.string.url_main); + String jsonStr = webreq.makeWebServiceCall(url1 + Utils.procFile(token, activityContext), WebRequest.GET); if (jsonStr != null && !jsonStr.isEmpty()) { try { @@ -128,7 +109,7 @@ public class RepoHelper { String manifestString = ""; boolean doUpdate = true; boolean hasCachedDate = false; - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); Map map = prefs.getAll(); for (Map.Entry entry : map.entrySet()) { if (entry.getValue().toString().contains(url)) { @@ -158,7 +139,6 @@ public class RepoHelper { Log.d("Magisk", "RepoHelper: DoUpdate is " + doUpdate); } - } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -185,14 +165,13 @@ public class RepoHelper { } return null; - } protected void onPostExecute(Void v) { if (apiFail) { Toast.makeText(activityContext, "GitHub API Limit reached, please try refreshing again in an hour.", Toast.LENGTH_LONG).show(); } else { - Log.d("Magisk","RepoHelper: postExecute fired"); + Log.d("Magisk", "RepoHelper: postExecute fired"); delegate.taskCompletionResult("Complete"); BuildFromCache(); @@ -200,12 +179,9 @@ public class RepoHelper { } } - protected void onPreExecute() { - - } public interface TaskDelegate { - public void taskCompletionResult(String result); + void taskCompletionResult(String result); } public class CustomComparator implements Comparator { @@ -215,5 +191,4 @@ public class RepoHelper { } } - } diff --git a/app/src/main/res/layout/list_item_module.xml b/app/src/main/res/layout/list_item_module.xml index 72c6951d5..d8eca5c10 100644 --- a/app/src/main/res/layout/list_item_module.xml +++ b/app/src/main/res/layout/list_item_module.xml @@ -14,16 +14,10 @@ card_view:cardCornerRadius="2dp" card_view:cardElevation="2dp"> - - - - + @@ -155,6 +149,7 @@ android:layout_height="wrap_content" android:layout_marginEnd="10dp" android:layout_marginStart="10dp" + android:backgroundTint="@color/icon_grey" android:background="@drawable/ic_changelog" /> @@ -181,6 +178,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_repo.xml b/app/src/main/res/layout/list_item_repo.xml index 39e09fae6..b8bcb8f61 100644 --- a/app/src/main/res/layout/list_item_repo.xml +++ b/app/src/main/res/layout/list_item_repo.xml @@ -14,16 +14,12 @@ card_view:cardCornerRadius="2dp" card_view:cardElevation="2dp"> - + android:padding="10dp"> @@ -128,6 +124,7 @@ android:layout_height="wrap_content" android:layout_marginStart="10dp" android:layout_marginEnd="10dp" + android:backgroundTint="@color/icon_grey" android:background="@drawable/ic_changelog"/> @@ -159,14 +158,14 @@ android:layout_height="wrap_content" android:focusable="false" android:visibility="gone" - android:gravity="right" + android:gravity="end" android:layout_marginStart="10dp" android:layout_marginEnd="10dp" /> - + diff --git a/app/src/main/res/layout/single_module_fragment.xml b/app/src/main/res/layout/single_module_fragment.xml index e6ab2c8fc..4b0e9f839 100644 --- a/app/src/main/res/layout/single_module_fragment.xml +++ b/app/src/main/res/layout/single_module_fragment.xml @@ -1,11 +1,12 @@ - + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/swipeRefreshLayout" + android:layout_width="match_parent" + android:layout_height="fill_parent" + android:layout_marginTop="?attr/actionBarSize" + android:orientation="vertical"> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 71526bc80..22207e784 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -6,7 +6,7 @@ #FFC107 #212121 #FFFFFF - + #757575 #F44336 #4CAF50 #2196F3 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1f072f42a..c1ad9d57b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -97,4 +97,5 @@ MagiskRox666 GTYybRBTYf5his9kQ16ZNO7qgkBJ/5MyVe4CGceAOIoXgSnnk8FTd4F1dE9p5Eus Downloads + https://api.github.com/orgs/Magisk-Modules-Repo/repos?access_token= From 145d4e4bd571fc30aad67a7f40d0e60713d11ae5 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Tue, 13 Sep 2016 07:31:43 -0500 Subject: [PATCH 21/27] Goddammit... Github likes to skip a file when I'm committing... --- .../com/topjohnwu/magisk/ModulesFragment.java | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index c3f64ee6a..3829c4dc8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -28,6 +28,7 @@ import com.nbsp.materialfilepicker.MaterialFilePicker; import com.nbsp.materialfilepicker.ui.FilePickerActivity; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.Repo; +import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.utils.Utils; import java.util.ArrayList; @@ -55,6 +56,7 @@ public class ModulesFragment extends Fragment { ViewPager viewPager; @BindView(R.id.tab_layout) TabLayout tabLayout; + private RepoHelper.TaskDelegate mTaskDelegate; @Nullable @Override @@ -64,8 +66,14 @@ public class ModulesFragment extends Fragment { ButterKnife.bind(this, view); new Utils.LoadModules(getActivity(), false).execute(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + mTaskDelegate = result -> { + if (result.equals("OK")) { + Log.d("Magisk","ModulesFragment: We dun got the result, hur hur."); + RefreshUI(); + } + + }; new updateUI().execute(); - setHasOptionsMenu(true); return view; } @@ -112,28 +120,21 @@ public class ModulesFragment extends Fragment { } } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.force_reload: - viewPagePosition = tabLayout.getSelectedTabPosition(); - listModules.clear(); - listModulesCache.clear(); - progressBar.setVisibility(View.VISIBLE); - viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); - tabLayout.setupWithViewPager(viewPager); - viewPager.setCurrentItem(viewPagePosition); - new Utils.LoadModules(getActivity(), true).execute(); - Collections.sort(listModules,new CustomComparator()); - Collections.sort(listModulesCache,new CustomComparator()); - new updateUI().execute(); - break; - } - - return super.onOptionsItemSelected(item); + private void RefreshUI() { + viewPagePosition = tabLayout.getSelectedTabPosition(); + listModules.clear(); + listModulesCache.clear(); + progressBar.setVisibility(View.VISIBLE); + viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); + tabLayout.setupWithViewPager(viewPager); + viewPager.setCurrentItem(viewPagePosition); + new Utils.LoadModules(getActivity(), true).execute(); + Collections.sort(listModules,new CustomComparator()); + Collections.sort(listModulesCache,new CustomComparator()); + new updateUI().execute(); } + void selectPage(int pageIndex) { tabLayout.setScrollPosition(pageIndex, 0f, true); viewPager.setCurrentItem(pageIndex); @@ -168,7 +169,6 @@ public class ModulesFragment extends Fragment { @Override protected void onPostExecute(Void v) { super.onPostExecute(v); - progressBar.setVisibility(View.GONE); viewPager.setAdapter(new TabsAdapter(getChildFragmentManager())); tabLayout.setupWithViewPager(viewPager); @@ -200,9 +200,13 @@ public class ModulesFragment extends Fragment { @Override public Fragment getItem(int position) { if (position == 0) { - return new NormalModuleFragment(); + NormalModuleFragment nmf = new NormalModuleFragment(); + nmf.SetDelegate(mTaskDelegate); + return nmf; } else { - return new CacheModuleFragment(); + CacheModuleFragment cmf = new CacheModuleFragment(); + cmf.SetDelegate(mTaskDelegate); + return cmf; } } } From 46abbfe2242cc29d9298cf531a54cf1e60b628fa Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Tue, 13 Sep 2016 15:44:07 -0500 Subject: [PATCH 22/27] More refinements... --- .../topjohnwu/magisk/BaseModuleFragment.java | 242 ++++++++++++------ .../com/topjohnwu/magisk/ReposAdapter.java | 62 +++-- .../com/topjohnwu/magisk/ReposFragment.java | 92 ++++++- .../com/topjohnwu/magisk/module/Module.java | 21 +- .../com/topjohnwu/magisk/module/Repo.java | 33 +-- .../topjohnwu/magisk/module/RepoHelper.java | 1 + 6 files changed, 324 insertions(+), 127 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index 829008885..ef1584aa9 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -3,13 +3,16 @@ package com.topjohnwu.magisk; import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; +import android.content.DialogInterface; import android.content.SharedPreferences; +import android.graphics.Color; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.AlertDialog; import android.support.v7.widget.RecyclerView; import android.util.DisplayMetrics; import android.util.Log; @@ -29,17 +32,22 @@ import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebWindow; +import java.io.File; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public abstract class BaseModuleFragment extends Fragment { - @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; - @BindView(R.id.recyclerView) RecyclerView recyclerView; - @BindView(R.id.empty_rv) TextView emptyTv; - + @BindView(R.id.swipeRefreshLayout) + SwipeRefreshLayout mSwipeRefreshLayout; + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + @BindView(R.id.empty_rv) + TextView emptyTv; + private RepoHelper.TaskDelegate mDelegate; private SharedPreferences prefs; @@ -55,13 +63,16 @@ public abstract class BaseModuleFragment extends Fragment { ButterKnife.bind(this, viewMain); - mSwipeRefreshLayout.setOnRefreshListener(() -> { - Log.d("Magisk","ModulesFragment: SWIPE"); - mDelegate.taskCompletionResult("OK"); - }); prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + mSwipeRefreshLayout.setOnRefreshListener(() -> { + + mDelegate.taskCompletionResult("OK"); + prefs.edit().putBoolean("ignoreUpdateAlerts", false).apply(); + + + }); prefs.registerOnSharedPreferenceChangeListener((sharedPreferences, s) -> { if (s.contains("updated")) { viewMain.invalidate(); @@ -98,6 +109,8 @@ public abstract class BaseModuleFragment extends Fragment { listModules().get(position).deleteRemoveFile(); Snackbar.make(undeleteBtn, R.string.remove_file_deleted, Snackbar.LENGTH_SHORT).show(); })); + + return viewMain; } @@ -107,20 +120,27 @@ public abstract class BaseModuleFragment extends Fragment { public class ModulesAdapter extends RecyclerView.Adapter { private final List mList; + private final List mListToUpdate = new ArrayList<>(); List mExpandedList; - @BindView(R.id.expand_layout) + @BindView(R.id.expand_layout) LinearLayout expandedLayout; private View viewMain; - private Context context; + private Context context; private final Utils.ItemClickListener chboxListener; private final Utils.ItemClickListener deleteBtnListener; private final Utils.ItemClickListener unDeleteBtnListener; + private boolean alertUpdate, ignoreAlertUpdate; public ModulesAdapter(List list, Utils.ItemClickListener chboxListener, Utils.ItemClickListener deleteBtnListener, Utils.ItemClickListener undeleteBtnListener) { + alertUpdate = false; this.mList = list; - mExpandedList = new ArrayList<>(mList.size()); + mExpandedList = new ArrayList<>(mList.size()); for (int i = 0; i < mList.size(); i++) { mExpandedList.add(false); + if (listModules().get(i).isUpdateAvailable()) { + alertUpdate = true; + mListToUpdate.add(listModules().get(i)); + } } this.chboxListener = chboxListener; this.deleteBtnListener = deleteBtnListener; @@ -130,43 +150,84 @@ public abstract class BaseModuleFragment extends Fragment { @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { viewMain = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_module, parent, false); - context = parent.getContext(); - ButterKnife.bind(this, viewMain); + context = parent.getContext(); + ButterKnife.bind(this, viewMain); return new ViewHolder(viewMain); } @Override public void onBindViewHolder(final ViewHolder holder, int position) { final Module module = mList.get(position); - Log.d("Magisk","ModulesAdapter: Trying set up bindview from list pos " + position + " and " + module.getName() ); - + Log.d("Magisk", "ModulesAdapter: Trying set up bindview from list pos " + position + " and " + module.getName()); + Log.d("Magisk", "BaseModuleFragment: Log ID is " + module.getmLogUrl()); holder.title.setText(module.getName()); holder.versionName.setText(module.getVersion()); holder.description.setText(module.getDescription()); holder.author.setText(module.getAuthor()); - + String logUrl = module.getmLogUrl(); + String supportUrl = module.getmSupportUrl(); + String donateUrl = module.getmDonateUrl(); + if (supportUrl != null && !supportUrl.isEmpty()) holder.supportLink.setBackgroundColor(Color.GRAY); + if (logUrl != null && !logUrl.isEmpty()) holder.changeLog.setBackgroundColor(Color.GRAY); + if (donateUrl != null && !donateUrl.isEmpty()) holder.authorLink.setBackgroundColor(Color.GRAY); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (prefs.contains("ignoreUpdateAlerts")) { + ignoreAlertUpdate = prefs.getBoolean("ignoreUpdateAlerts", false); + } if (prefs.contains("repo-canUpdate_" + module.getId())) { - if (prefs.getBoolean("repo-canUpdate_" + module.getId(),false)) { + if (prefs.getBoolean("repo-canUpdate_" + module.getId(), false)) { holder.updateStatus.setText(R.string.module_update_available); holder.updateStatus.setVisibility(View.VISIBLE); } else { holder.updateStatus.setVisibility(View.GONE); } + + if (alertUpdate && !ignoreAlertUpdate) { + Iterator iterRepo = mListToUpdate.iterator(); + while (iterRepo.hasNext()) { + Module mModule = iterRepo.next(); + DialogInterface.OnClickListener dialogClickListener = (dialog, which) -> { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + Utils.DownloadReceiver receiver = new Utils.DownloadReceiver() { + @Override + public void task(File file) { + Log.d("Magisk", "Task firing"); + new Utils.FlashZIP(context, mModule.getId(), file.toString()).execute(); + } + }; + String filename = mModule.getId().replace(" ", "") + ".zip"; + Utils.downloadAndReceive(context, receiver, mModule.getmZipUrl(), filename); + + break; + + case DialogInterface.BUTTON_NEGATIVE: + ignoreAlertUpdate = true; + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("ignoreUpdateAlerts", ignoreAlertUpdate); + editor.apply(); + break; + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setMessage("An update is available for " + mModule.getName() + ". Would you like to install it?").setPositiveButton("Yes", dialogClickListener) + .setNegativeButton("No", dialogClickListener).show(); + mListToUpdate.remove(mModule); + } + } } - View.OnClickListener oCl = new View.OnClickListener() { - @Override - public void onClick(View view) { - if (view.getId() == holder.changeLog.getId()) { - new WebWindow("Changelog",module.getChangeLog(),context); - } - if (view.getId() == holder.authorLink.getId()) { - new WebWindow("Donate",module.getmDonateUrl(),context); - } - if (view.getId() == holder.supportLink.getId()) { - new WebWindow("Support",module.getmSupportUrl(),context); - } + View.OnClickListener oCl = view -> { + if (view.getId() == holder.changeLog.getId()) { + + new WebWindow("Changelog", module.getmLogUrl(), context); + } + if (view.getId() == holder.authorLink.getId()) { + new WebWindow("Donate", module.getmDonateUrl(), context); + } + if (view.getId() == holder.supportLink.getId()) { + new WebWindow("Support", module.getmSupportUrl(), context); } }; @@ -206,19 +267,31 @@ public abstract class BaseModuleFragment extends Fragment { class ViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.title) TextView title; + @BindView(R.id.title) + TextView title; - @BindView(R.id.version_name) TextView versionName; - @BindView(R.id.description) TextView description; - @BindView(R.id.warning) TextView warning; - @BindView(R.id.checkbox) CheckBox checkBox; - @BindView(R.id.author) TextView author; - @BindView(R.id.updateStatus) TextView updateStatus; - @BindView(R.id.delete) ImageView delete; - @BindView(R.id.changeLog) ImageView changeLog; - @BindView(R.id.authorLink) ImageView authorLink; - @BindView(R.id.supportLink) ImageView supportLink; - @BindView(R.id.expand_layout) LinearLayout expandLayout; + @BindView(R.id.version_name) + TextView versionName; + @BindView(R.id.description) + TextView description; + @BindView(R.id.warning) + TextView warning; + @BindView(R.id.checkbox) + CheckBox checkBox; + @BindView(R.id.author) + TextView author; + @BindView(R.id.updateStatus) + TextView updateStatus; + @BindView(R.id.delete) + ImageView delete; + @BindView(R.id.changeLog) + ImageView changeLog; + @BindView(R.id.authorLink) + ImageView authorLink; + @BindView(R.id.supportLink) + ImageView supportLink; + @BindView(R.id.expand_layout) + LinearLayout expandLayout; private ValueAnimator mAnimator; private int mMeasuredHeight; @@ -226,19 +299,19 @@ public abstract class BaseModuleFragment extends Fragment { super(itemView); WindowManager windowmanager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); ButterKnife.bind(this, itemView); - DisplayMetrics dimension = new DisplayMetrics(); + DisplayMetrics dimension = new DisplayMetrics(); windowmanager.getDefaultDisplay().getMetrics(dimension); - final int mHeight = dimension.heightPixels; expandLayout.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { + @Override public boolean onPreDraw() { expandLayout.getViewTreeObserver().removeOnPreDrawListener(this); expandLayout.setVisibility(View.GONE); final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - final int heightSpec = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); + final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); expandLayout.measure(widthSpec, heightSpec); mAnimator = slideAnimator(0, expandLayout.getMeasuredHeight()); return true; @@ -262,58 +335,59 @@ public abstract class BaseModuleFragment extends Fragment { delete.setEnabled(false); } } - private void expand(View view) { - // set Visible + private void expand(View view) { + + // set Visible - Log.d("Magisk", "ReposFragment: Expand anim called " + mMeasuredHeight + " and " + view.getId()); - view.setVisibility(View.VISIBLE); - mAnimator.start(); - } + Log.d("Magisk", "ReposFragment: Expand anim called " + mMeasuredHeight + " and " + view.getId()); + view.setVisibility(View.VISIBLE); + mAnimator.start(); + } - private void collapse(View view) { - int finalHeight = view.getHeight(); - ValueAnimator mAnimator = slideAnimator(finalHeight, 0); - Log.d("Magisk", "ReposFragment: Collapse anim called " + finalHeight + " and " + view.getId()); + private void collapse(View view) { + int finalHeight = view.getHeight(); + ValueAnimator mAnimator = slideAnimator(finalHeight, 0); + Log.d("Magisk", "ReposFragment: Collapse anim called " + finalHeight + " and " + view.getId()); - mAnimator.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationEnd(Animator animator) { - // Height=0, but it set visibility to GONE - view.setVisibility(View.GONE); - } + mAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationEnd(Animator animator) { + // Height=0, but it set visibility to GONE + view.setVisibility(View.GONE); + } - @Override - public void onAnimationStart(Animator animator) { - } + @Override + public void onAnimationStart(Animator animator) { + } - @Override - public void onAnimationCancel(Animator animator) { - } + @Override + public void onAnimationCancel(Animator animator) { + } - @Override - public void onAnimationRepeat(Animator animator) { - } - }); - mAnimator.start(); - } + @Override + public void onAnimationRepeat(Animator animator) { + } + }); + mAnimator.start(); + } - private ValueAnimator slideAnimator(int start, int end) { + private ValueAnimator slideAnimator(int start, int end) { - ValueAnimator animator = ValueAnimator.ofInt(start, end); + ValueAnimator animator = ValueAnimator.ofInt(start, end); - animator.addUpdateListener(valueAnimator -> { - // Update Height - int value = (Integer) valueAnimator.getAnimatedValue(); + animator.addUpdateListener(valueAnimator -> { + // Update Height + int value = (Integer) valueAnimator.getAnimatedValue(); - ViewGroup.LayoutParams layoutParams = expandLayout - .getLayoutParams(); - layoutParams.height = value; - expandLayout.setLayoutParams(layoutParams); - }); - return animator; - } + ViewGroup.LayoutParams layoutParams = expandLayout + .getLayoutParams(); + layoutParams.height = value; + expandLayout.setLayoutParams(layoutParams); + }); + return animator; + } } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java index 9adb8bbb4..26f136e66 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposAdapter.java @@ -33,24 +33,37 @@ import butterknife.ButterKnife; public class ReposAdapter extends RecyclerView.Adapter { - private ReposFragment reposFragment; private final List mList; List mExpandedList; private View viewMain; private Context context; - private boolean mIsInstalled, mCanUpdate; + private boolean mCanUpdate; + private boolean alertUpdate; + private boolean ignoreAlertUpdate; private Repo repo; private ViewHolder mHolder; + private String mDonateUrl, mSupportUrl, mLogUrl,alertPackage; + private SharedPreferences prefs; + public ReposAdapter(ReposFragment reposFragment, List list) { - this.reposFragment = reposFragment; + ReposFragment reposFragment1 = reposFragment; + alertPackage = ""; + alertUpdate = false; this.mList = list; Log.d("Magisk", "ReposAdapter: I am alive. I have a list " + list.size()); mExpandedList = new ArrayList<>(mList.size()); for (int i = 0; i < mList.size(); i++) { mExpandedList.add(false); + if (mList.get(i).canUpdate()) { + alertUpdate = true; + if (alertPackage.equals("")) { + alertPackage = mList.get(i).getName(); + } else { + alertPackage += mList.get(i).getName() + ", "; + } + } } - } @Override @@ -75,17 +88,21 @@ public class ReposAdapter extends RecyclerView.Adapter @Override public void onBindViewHolder(final ViewHolder holder, int position) { + prefs = PreferenceManager.getDefaultSharedPreferences(context); repo = mList.get(position); mHolder = holder; + mDonateUrl = repo.getmDonateUrl(); + mSupportUrl = repo.getmSupportUrl(); + mLogUrl = repo.getmLogUrl(); mExpandedList = new ArrayList<>(mList.size()); for (int i = 0; i < mList.size(); i++) { mExpandedList.add(false); } - SetupViewElements(); + SetupViewElements(repo); } - private void SetupViewElements() { + private void SetupViewElements(Repo repo) { int mPosition = mHolder.getAdapterPosition(); String titleString; if (repo.getId() != null) { @@ -100,26 +117,37 @@ public class ReposAdapter extends RecyclerView.Adapter mHolder.description.setText(repo.getDescription()); String authorString = this.context.getResources().getString(R.string.author) + " " + repo.getmAuthor(); mHolder.author.setText(authorString); + String logUrl = repo.getmLogUrl(); + String supportUrl = repo.getmSupportUrl(); + String donateUrl = repo.getmDonateUrl(); + if (supportUrl.equals("")) mHolder.supportLink.setBackgroundColor(Color.GRAY); + if (logUrl.equals("")) mHolder.changeLog.setBackgroundColor(Color.GRAY); + if (donateUrl.equals("")) mHolder.authorLink.setBackgroundColor(Color.GRAY); + if (prefs.contains("ignoreUpdateAlerts")) { + ignoreAlertUpdate = prefs.getBoolean("ignoreUpdateAlerts",false); + } mHolder.installedStatus.setText(repo.isInstalled() ? this.context.getResources().getString(R.string.module_installed) : this.context.getResources().getString(R.string.module_not_installed)); if (mExpandedList.get(mPosition)) { mHolder.expandLayout.setVisibility(View.VISIBLE); } else { mHolder.expandLayout.setVisibility(View.GONE); } + if (repo.isInstalled()) { mHolder.installedStatus.setTextColor(Color.parseColor("#14AD00")); mHolder.updateStatus.setText(repo.canUpdate() ? this.context.getResources().getString(R.string.module_update_available) : this.context.getResources().getString(R.string.module_up_to_date)); } Log.d("Magisk", "ReposAdapter: Setting up info " + repo.getId() + " and " + repo.getDescription() + " and " + repo.getmVersion()); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - mCanUpdate = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); + prefs = PreferenceManager.getDefaultSharedPreferences(context); + mCanUpdate = prefs.getBoolean("repo-canUpdate_" + repo.getId(), false); + View.OnClickListener oCl = view -> { Log.d("Magisk", "Onlick captured, view is " + view.getId()); if (view.getId() == mHolder.updateImage.getId()) { - if (!mIsInstalled | mCanUpdate) { + if (!repo.isInstalled() | repo.canUpdate()) { Utils.DownloadReceiver receiver = new Utils.DownloadReceiver() { @Override @@ -134,14 +162,14 @@ public class ReposAdapter extends RecyclerView.Adapter Toast.makeText(context, repo.getId() + " is already installed.", Toast.LENGTH_SHORT).show(); } } - if (view.getId() == mHolder.changeLog.getId()) { - new WebWindow("Changelog", repo.getmLogText(), this.context); + if ((view.getId() == mHolder.changeLog.getId()) && (!repo.getmLogUrl().equals(""))) { + new WebWindow("Changelog", repo.getmLogUrl(),context); } - if (view.getId() == mHolder.authorLink.getId()) { - new WebWindow("Donate", repo.getmDonateUrl(), this.context); + if ((view.getId() == mHolder.authorLink.getId()) && (!repo.getmSupportUrl().equals(""))) { + new WebWindow("Donate", repo.getmDonateUrl(),context); } - if (view.getId() == mHolder.supportLink.getId()) { - new WebWindow("Support", repo.getmSupportUrl(), this.context); + if ((view.getId() == mHolder.supportLink.getId()) && (!repo.getmSupportUrl().equals(""))) { + new WebWindow("Support", repo.getmSupportUrl(),context); } }; mHolder.changeLog.setOnClickListener(oCl); @@ -149,13 +177,15 @@ public class ReposAdapter extends RecyclerView.Adapter mHolder.authorLink.setOnClickListener(oCl); mHolder.supportLink.setOnClickListener(oCl); if (prefs.contains("repo-isInstalled_" + repo.getId())) { - mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); + boolean mIsInstalled = prefs.getBoolean("repo-isInstalled_" + repo.getId(), false); } } } + + @Override public int getItemCount() { return mList.size(); diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java index 72e0300c2..c4c6b8a64 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -1,11 +1,15 @@ package com.topjohnwu.magisk; import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.AlertDialog; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; @@ -15,8 +19,11 @@ import android.widget.TextView; import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.module.RepoHelper; +import com.topjohnwu.magisk.utils.Utils; +import java.io.File; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import butterknife.BindView; @@ -25,41 +32,83 @@ import butterknife.ButterKnife; public class ReposFragment extends Fragment { public static List mListRepos = new ArrayList<>(); + public static List mListReposToUpdate = new ArrayList<>(); @BindView(R.id.recyclerView) RecyclerView recyclerView; @BindView(R.id.empty_rv) TextView emptyTv; @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout; + private View mView; + private boolean mCanUpdate; + private boolean alertUpdate; + private boolean ignoreAlertUpdate; + private String alertPackage; + private SharedPreferences prefs; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.single_repo_fragment, container, false); + mView = view; ButterKnife.bind(this, view); + prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); + if (prefs.contains("ignoreUpdateAlerts")) { + ignoreAlertUpdate = prefs.getBoolean("ignoreUpdateAlerts", false); + } swipeRefreshLayout.setOnRefreshListener(() -> { - Log.d("Magisk","ReposFragment: WTF IM CALLED"); this.LoadRepo(true); + ignoreAlertUpdate = false; + prefs.edit().putBoolean("ignoreUpdateAlerts",false).apply(); + }); LoadRepo(false); setHasOptionsMenu(false); - + alertUpdate = false; if (mListRepos.size() == 0) { emptyTv.setVisibility(View.VISIBLE); recyclerView.setVisibility(View.GONE); return view; } + CheckForUpdates(); Log.d("Magisk", "ReposFragment: ListRepos size is " + listRepos().size()); recyclerView.setAdapter(new ReposAdapter(this, mListRepos)); return view; } + @Override + public void onStart() { + super.onStart(); + NotifyOfAlerts(); + + } + + private void CheckForUpdates() { + for (int i = 0; i < mListRepos.size(); i++) { + if (mListRepos.get(i).canUpdate()) { + alertUpdate = true; + mListReposToUpdate.add(mListRepos.get(i)); + + } + } + } + + @Override + public void onAttachFragment(Fragment childFragment) { + super.onAttachFragment(childFragment); + } + private void LoadRepo (boolean doReload) { RepoHelper.TaskDelegate taskDelegate = result -> { if (result.equals("Complete")) { Log.d("Magisk", "ReposFragment, got delegate"); UpdateUI(); + if (mView != null) { + mView.invalidate(); + mView.requestLayout(); + } + } }; @@ -75,6 +124,43 @@ public class ReposFragment extends Fragment { } + private void NotifyOfAlerts() { + if (alertUpdate && !ignoreAlertUpdate) { + Iterator iterRepo = mListReposToUpdate.iterator(); + while (iterRepo.hasNext()) { + Repo repo = iterRepo.next(); + DialogInterface.OnClickListener dialogClickListener = (dialog, which) -> { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + Utils.DownloadReceiver receiver = new Utils.DownloadReceiver() { + @Override + public void task(File file) { + Log.d("Magisk", "Task firing"); + new Utils.FlashZIP(getActivity(), repo.getId(), file.toString()).execute(); + } + }; + String filename = repo.getId().replace(" ", "") + ".zip"; + Utils.downloadAndReceive(getActivity(), receiver, repo.getmZipUrl(), filename); + + break; + + case DialogInterface.BUTTON_NEGATIVE: + ignoreAlertUpdate = true; + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("ignoreUpdateAlerts", ignoreAlertUpdate); + editor.apply(); + break; + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setMessage("An update is available for " + repo.getName() + ". Would you like to install it?").setPositiveButton("Yes", dialogClickListener) + .setNegativeButton("No", dialogClickListener).show(); + iterRepo.remove(); + } + + } + } @Override @@ -102,6 +188,8 @@ public class ReposFragment extends Fragment { recyclerView.setAdapter(new ReposAdapter(this, listRepos())); if (swipeRefreshLayout.isRefreshing()) { swipeRefreshLayout.setRefreshing(false); + CheckForUpdates(); + NotifyOfAlerts(); } 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 32034b1d2..f052971be 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Module.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Module.java @@ -16,7 +16,7 @@ public class Module { private String mVersion = "(No version provided)"; private String mDescription = "(No description provided)"; private String mUrl,mSupportUrl,mDonateUrl,mZipUrl,mBaseUrl,mManifestUrl,mAuthor,mLogUrl; - private boolean mEnable, mRemove,mUpdateAvailable,mIsOnline,mIsCacheModule; + private boolean mEnable, mRemove,mUpdateAvailable, mIsInstalled,mIsCacheModule; private String mId; @@ -81,12 +81,13 @@ public class Module { this.mLogUrl = props[1]; break; default: - Log.d("Magisk", "Manifest string not recognized: " + props[0]); + Log.d("Magisk", "Module: Manifest string not recognized: " + props[0]); break; } } + Log.d("Magisk","Module: Loaded module with ID of " + this.mId + " or " + mId); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); @@ -97,7 +98,6 @@ public class Module { if (!preferenceKey.equals("nope")) { Log.d("Magisk", "Module: repo_" + mId + " found."); String entryString = prefs.getString("repo_" + mId, ""); - String[] subStrings = entryString.split("\n"); for (String subKeys : subStrings) { String[] idEntry = subKeys.split("=", 2); @@ -107,9 +107,9 @@ public class Module { } if (idEntry[1].equals(mId)) { - Log.d("Magisk", "Module: Hey, I know I'm online..."); - mIsOnline = true; - } else mIsOnline = false; + Log.d("Magisk", "Module: Hey, I know " + mId + " is online..."); + mIsInstalled = true; + } else mIsInstalled = false; } if (idEntry[0].equals("logUrl")) { mLogUrl = idEntry[1]; @@ -140,9 +140,8 @@ public class Module { } SharedPreferences.Editor editor = prefs.edit(); - if (mIsOnline) { + if (mIsInstalled) { editor.putBoolean("repo-isInstalled_" + mId, true); - } else { editor.putBoolean("repo-isInstalled_" + mId, false); } @@ -195,7 +194,7 @@ public class Module { public String getId() {return mId; } - public String getChangeLog() {return mLogUrl; } + public String getmLogUrl() {return mLogUrl; } public String getDescription() { return mDescription; @@ -229,6 +228,8 @@ public class Module { return mDonateUrl; } + public String getmZipUrl() { return mZipUrl; } + public String getmManifestUrl() { return mManifestUrl; } @@ -237,7 +238,7 @@ public class Module { return mSupportUrl; } - public boolean isOnline() {return mIsOnline; } + public boolean isInstalled() {return mIsInstalled; } public boolean isUpdateAvailable() { return mUpdateAvailable; } diff --git a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java index 948d92f70..23c74dcdf 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/Repo.java @@ -18,7 +18,7 @@ import java.util.Date; public class Repo { private String mBaseUrl; private String mZipUrl; - private String mLogText; + private String mLogUrl; private String mManifestUrl; private String mVersion; private String mName; @@ -72,14 +72,17 @@ public class Repo { for (int f = 0; f < repoArray.length(); f++) { JSONObject jsonobject = repoArray.getJSONObject(f); String name = jsonobject.getString("name"); + String url = jsonobject.getString("download_url").trim(); + Log.d("Magisk","Repo - checking object named " + name + " with value of " + url); if (name.contains(".zip")) { - this.mZipUrl = jsonobject.getString("download_url"); - } else if (name.equals("module.prop")) { - this.mManifestUrl = jsonobject.getString("download_url"); - } else if (name.equals("changelog.txt")) { - String logUrl = jsonobject.getString("download_url");; - String logText = webreq.makeWebServiceCall(logUrl,WebRequest.GET); - this.mLogText = logText; + this.mZipUrl = url; + } + if (name.equals("module.prop")) { + this.mManifestUrl = url; + } + if (name.contains("log.txt")) { + Log.d("Magisk","Repo: Setting log URL for " + name + " of " + url); + this.mLogUrl = url; } } } catch (JSONException e) { @@ -96,10 +99,9 @@ public class Repo { } private void PutProps(String manifestString) { - manifestString = manifestString + "zipUrl=" + mZipUrl + "\nbaseUrl=" + mBaseUrl + "\nmanifestUrl=" + mManifestUrl; + manifestString = manifestString + "zipUrl=" + mZipUrl + "\nbaseUrl=" + mBaseUrl + "\nlogUrl=" + mLogUrl + "\nmanifestUrl=" + mManifestUrl; SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext); SharedPreferences.Editor editor = prefs.edit(); - editor.putString("log_" + mId, mLogText); editor.putString("repo_" + mId, manifestString); editor.putBoolean("hasCachedRepos", true); editor.putString("updated_" + mId, this.lastUpdate); @@ -142,6 +144,9 @@ public class Repo { case "support": this.mSupportUrl = props[1]; break; + case "logUrl": + this.mLogUrl = props[1]; + break; case "donateUrl": this.mDonateUrl = props[1]; break; @@ -171,9 +176,7 @@ public class Repo { if (prefs.contains("updated_" + this.mId)) { lastUpdate = prefs.getString("updated_" + this.mId,""); } - if (prefs.contains("log_" + this.mId)) { - mLogText = prefs.getString("log_" + this.mId,""); - } + return this.mId != null; @@ -239,8 +242,8 @@ public class Repo { return mBaseUrl; } - public String getmLogText() { - return mLogText; + public String getmLogUrl() { + return mLogUrl; } diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java index 61a534b45..3960a59f2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java @@ -80,6 +80,7 @@ public class RepoHelper { @Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); + prefs.edit().putBoolean("ignoreUpdateAlerts", false).apply(); Toast.makeText(activityContext, "Refreshing online modules", Toast.LENGTH_SHORT).show(); } From 6a90340b149217b317bdb388f6881c5a331ca289 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Wed, 14 Sep 2016 17:12:47 -0500 Subject: [PATCH 23/27] Work on file picker - WIP --- app/build.gradle | 6 +- app/src/main/AndroidManifest.xml | 4 + .../topjohnwu/magisk/BaseModuleFragment.java | 3 - .../com/topjohnwu/magisk/ModulesFragment.java | 106 ++++++++++-------- .../topjohnwu/magisk/module/RepoHelper.java | 4 + 5 files changed, 69 insertions(+), 54 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5427eb416..d3eebbbba 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,9 +26,7 @@ android { } } repositories { - maven { - url "http://dl.bintray.com/lukaville/maven" - } + } dependencies { @@ -36,7 +34,7 @@ dependencies { compile 'com.android.support:recyclerview-v7:24.2.0' compile 'com.android.support:cardview-v7:24.2.0' compile 'com.android.support:design:24.2.0' - compile 'com.nbsp:library:1.1' compile 'com.jakewharton:butterknife:8.4.0' + compile 'com.github.angads25:filepicker:1.0.6' annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4e518ad8..7dd7816f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,6 +16,7 @@ tools:ignore="AllowBackup,GoogleAppIndexingWarning"> @@ -23,9 +24,11 @@ + + + \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java index ef1584aa9..e5fe56942 100644 --- a/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/BaseModuleFragment.java @@ -167,9 +167,6 @@ public abstract class BaseModuleFragment extends Fragment { String logUrl = module.getmLogUrl(); String supportUrl = module.getmSupportUrl(); String donateUrl = module.getmDonateUrl(); - if (supportUrl != null && !supportUrl.isEmpty()) holder.supportLink.setBackgroundColor(Color.GRAY); - if (logUrl != null && !logUrl.isEmpty()) holder.changeLog.setBackgroundColor(Color.GRAY); - if (donateUrl != null && !donateUrl.isEmpty()) holder.authorLink.setBackgroundColor(Color.GRAY); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); if (prefs.contains("ignoreUpdateAlerts")) { ignoreAlertUpdate = prefs.getBoolean("ignoreUpdateAlerts", false); diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 3829c4dc8..1ecf536e2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -2,40 +2,46 @@ package com.topjohnwu.magisk; import android.app.Activity; import android.content.Intent; -import android.content.SharedPreferences; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.preference.PreferenceManager; +import android.os.Environment; +import android.provider.DocumentsContract; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.provider.DocumentFile; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; -import android.widget.Toast; -import com.nbsp.materialfilepicker.MaterialFilePicker; -import com.nbsp.materialfilepicker.ui.FilePickerActivity; + +import com.github.angads25.filepicker.controller.DialogSelectionListener; +import com.github.angads25.filepicker.model.DialogConfigs; +import com.github.angads25.filepicker.model.DialogProperties; +import com.github.angads25.filepicker.view.FilePickerDialog; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.lib; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.regex.Pattern; import butterknife.BindView; import butterknife.ButterKnife; @@ -44,9 +50,7 @@ public class ModulesFragment extends Fragment { public static List listModules = new ArrayList<>(); public static List listModulesCache = new ArrayList<>(); - private static final int FILE_SELECT_CODE = 0; private int viewPagePosition; - private static final int RESULT_OK = 1; @BindView(R.id.progressBar) ProgressBar progressBar; @@ -57,6 +61,7 @@ public class ModulesFragment extends Fragment { @BindView(R.id.tab_layout) TabLayout tabLayout; private RepoHelper.TaskDelegate mTaskDelegate; + private static final int RQS_OPEN_DOCUMENT_TREE = 2; @Nullable @Override @@ -64,61 +69,67 @@ public class ModulesFragment extends Fragment { View view = inflater.inflate(R.layout.modules_fragment, container, false); ButterKnife.bind(this, view); + String[] extensions = new String[1]; + extensions[0] = "zip"; + fabio.setOnClickListener(v -> { + Intent fileintent = new Intent(Intent.ACTION_GET_CONTENT); + fileintent.setType("application/zip"); + startActivityForResult(fileintent, RQS_OPEN_DOCUMENT_TREE); + + + }); + new Utils.LoadModules(getActivity(), false).execute(); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); mTaskDelegate = result -> { if (result.equals("OK")) { - Log.d("Magisk","ModulesFragment: We dun got the result, hur hur."); + Log.d("Magisk", "ModulesFragment: We dun got the result, hur hur."); RefreshUI(); } }; + new updateUI().execute(); return view; } + + public static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + String file = ""; + if(resultCode == Activity.RESULT_OK && requestCode == RQS_OPEN_DOCUMENT_TREE){ + if (isExternalStorageDocument(data.getData())) { + final String docId = DocumentsContract.getDocumentId(data.getData()); + final String[] split = docId.split(":"); + final String type = split[0]; + + if ("primary".equalsIgnoreCase(type)) { + file = Environment.getExternalStorageDirectory() + "/" + split[1]; + } + + // TODO handle non-primary volumes + } + String shit = data.getDataString(); + + Log.d("Magisk","ModulesFragment: Got a result, " + shit + " and " + data.getData().getAuthority() + " and " + file); + + } + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_module, menu); - fabio.setOnClickListener(view -> { - openFilePicker(); - }); + } - private void openFilePicker() { - new MaterialFilePicker() - .withSupportFragment(this) - .withFilter(Pattern.compile(".*\\.zip$")) - .withRequestCode(FILE_SELECT_CODE) - .withHiddenFiles(true) - .start(); - } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - Log.d("Magisk","WelcomeActivity: Got an OK result" + resultCode); - if (resultCode == Activity.RESULT_OK) { - String path = data.getStringExtra(FilePickerActivity.RESULT_FILE_PATH); - Log.d("Magisk","ModuleFragment: Got an OK result " + path); - if (path != null) { - Log.d("Path: ", path); - Toast.makeText(getActivity(), "Picked file: " + path, Toast.LENGTH_LONG).show(); - // Get the Uri of the selected file - String filePath = data.getStringExtra(FilePickerActivity.RESULT_FILE_PATH); - Uri uri = Uri.parse(filePath); - - path = uri.getPath(); - Log.d("Magisk","ModuleFragment: Got an OK result " + filePath + " and " + uri.toString() + " and " + path); - - String fileName = uri.getLastPathSegment(); - new Utils.FlashZIP(getActivity(), fileName, path).execute(); - } - } - } private void RefreshUI() { viewPagePosition = tabLayout.getSelectedTabPosition(); @@ -129,8 +140,8 @@ public class ModulesFragment extends Fragment { tabLayout.setupWithViewPager(viewPager); viewPager.setCurrentItem(viewPagePosition); new Utils.LoadModules(getActivity(), true).execute(); - Collections.sort(listModules,new CustomComparator()); - Collections.sort(listModulesCache,new CustomComparator()); + Collections.sort(listModules, new CustomComparator()); + Collections.sort(listModulesCache, new CustomComparator()); new updateUI().execute(); } @@ -210,6 +221,7 @@ public class ModulesFragment extends Fragment { } } } + public class CustomComparator implements Comparator { @Override public int compare(Module o1, Module o2) { diff --git a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java index 3960a59f2..f360be9cd 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/RepoHelper.java @@ -18,6 +18,7 @@ import org.json.JSONObject; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -43,6 +44,9 @@ public class RepoHelper { if (!prefs.contains("hasCachedRepos") | refresh) { Log.d(TAG, "RepoHelper: Building from web"); new BuildFromWeb(delegate).execute(); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); + String date = format.format(Calendar.getInstance().getTime()); + prefs.edit().putString("last_update",date).apply(); } else { Log.d(TAG, "RepoHelper: Building from cache"); BuildFromCache(); From c5a73a5c1977c9316642d8a810c8560e249ef6d6 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Wed, 14 Sep 2016 17:29:35 -0500 Subject: [PATCH 24/27] Code cleanup --- .../com/topjohnwu/magisk/ModulesFragment.java | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 1ecf536e2..3404bd956 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -13,7 +13,6 @@ import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.provider.DocumentFile; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.LayoutInflater; @@ -23,21 +22,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; - -import com.github.angads25.filepicker.controller.DialogSelectionListener; -import com.github.angads25.filepicker.model.DialogConfigs; -import com.github.angads25.filepicker.model.DialogProperties; -import com.github.angads25.filepicker.view.FilePickerDialog; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.utils.lib; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -69,8 +57,6 @@ public class ModulesFragment extends Fragment { View view = inflater.inflate(R.layout.modules_fragment, container, false); ButterKnife.bind(this, view); - String[] extensions = new String[1]; - extensions[0] = "zip"; fabio.setOnClickListener(v -> { Intent fileintent = new Intent(Intent.ACTION_GET_CONTENT); fileintent.setType("application/zip"); @@ -101,21 +87,21 @@ public class ModulesFragment extends Fragment { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { String file = ""; - if(resultCode == Activity.RESULT_OK && requestCode == RQS_OPEN_DOCUMENT_TREE){ + if (resultCode == Activity.RESULT_OK && requestCode == RQS_OPEN_DOCUMENT_TREE) { if (isExternalStorageDocument(data.getData())) { final String docId = DocumentsContract.getDocumentId(data.getData()); final String[] split = docId.split(":"); final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { - file = Environment.getExternalStorageDirectory() + "/" + split[1]; + file = Environment.getExternalStorageDirectory() + "/" + split[1]; } // TODO handle non-primary volumes } String shit = data.getDataString(); - Log.d("Magisk","ModulesFragment: Got a result, " + shit + " and " + data.getData().getAuthority() + " and " + file); + Log.d("Magisk", "ModulesFragment: Got a result, " + shit + " and " + data.getData().getAuthority() + " and " + file); } } @@ -129,8 +115,6 @@ public class ModulesFragment extends Fragment { } - - private void RefreshUI() { viewPagePosition = tabLayout.getSelectedTabPosition(); listModules.clear(); From 8f973661f4518e675c27662120fd644f36d71ab8 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Thu, 15 Sep 2016 07:35:12 -0500 Subject: [PATCH 25/27] Still can't open URI's for ZIP files on external storage, but we're close... --- app/build.gradle | 5 +- .../com/topjohnwu/magisk/ModulesFragment.java | 50 +++------- .../com/topjohnwu/magisk/utils/Utils.java | 93 ++++++++++++++++++- 3 files changed, 103 insertions(+), 45 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d3eebbbba..f0fe1579d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,7 +26,8 @@ android { } } repositories { - + jcenter() + maven { url "https://jitpack.io" } } dependencies { @@ -35,6 +36,6 @@ dependencies { compile 'com.android.support:cardview-v7:24.2.0' compile 'com.android.support:design:24.2.0' compile 'com.jakewharton:butterknife:8.4.0' - compile 'com.github.angads25:filepicker:1.0.6' + compile 'com.github.michalis-vitos:aFileChooser:master' annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' } diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 3404bd956..93110915b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -5,8 +5,6 @@ import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Environment; -import android.provider.DocumentsContract; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.TabLayout; @@ -14,7 +12,6 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -36,10 +33,9 @@ import butterknife.ButterKnife; public class ModulesFragment extends Fragment { + private static final int FETCH_ZIP_CODE = 2; public static List listModules = new ArrayList<>(); public static List listModulesCache = new ArrayList<>(); - private int viewPagePosition; - @BindView(R.id.progressBar) ProgressBar progressBar; @BindView(R.id.fab) @@ -48,8 +44,8 @@ public class ModulesFragment extends Fragment { ViewPager viewPager; @BindView(R.id.tab_layout) TabLayout tabLayout; + private int viewPagePosition; private RepoHelper.TaskDelegate mTaskDelegate; - private static final int RQS_OPEN_DOCUMENT_TREE = 2; @Nullable @Override @@ -58,17 +54,16 @@ public class ModulesFragment extends Fragment { ButterKnife.bind(this, view); fabio.setOnClickListener(v -> { - Intent fileintent = new Intent(Intent.ACTION_GET_CONTENT); - fileintent.setType("application/zip"); - startActivityForResult(fileintent, RQS_OPEN_DOCUMENT_TREE); - + Intent fileIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + fileIntent.setType("application/zip"); + fileIntent.addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult(fileIntent, FETCH_ZIP_CODE); }); new Utils.LoadModules(getActivity(), false).execute(); mTaskDelegate = result -> { if (result.equals("OK")) { - Log.d("Magisk", "ModulesFragment: We dun got the result, hur hur."); RefreshUI(); } @@ -78,31 +73,14 @@ public class ModulesFragment extends Fragment { return view; } - - public static boolean isExternalStorageDocument(Uri uri) { - return "com.android.externalstorage.documents".equals(uri.getAuthority()); - } - - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - String file = ""; - if (resultCode == Activity.RESULT_OK && requestCode == RQS_OPEN_DOCUMENT_TREE) { - if (isExternalStorageDocument(data.getData())) { - final String docId = DocumentsContract.getDocumentId(data.getData()); - final String[] split = docId.split(":"); - final String type = split[0]; - - if ("primary".equalsIgnoreCase(type)) { - file = Environment.getExternalStorageDirectory() + "/" + split[1]; - } - - // TODO handle non-primary volumes - } - String shit = data.getDataString(); - - Log.d("Magisk", "ModulesFragment: Got a result, " + shit + " and " + data.getData().getAuthority() + " and " + file); - + Uri mUri = data.getData(); + final int takeFlags = data.getFlags() + & (Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + if (resultCode == Activity.RESULT_OK && requestCode == FETCH_ZIP_CODE) { + new Utils.FlashZIP(getActivity(), mUri, takeFlags).execute(); } } @@ -111,10 +89,8 @@ public class ModulesFragment extends Fragment { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_module, menu); - } - private void RefreshUI() { viewPagePosition = tabLayout.getSelectedTabPosition(); listModules.clear(); @@ -129,7 +105,6 @@ public class ModulesFragment extends Fragment { new updateUI().execute(); } - void selectPage(int pageIndex) { tabLayout.setScrollPosition(pageIndex, 0f, true); viewPager.setCurrentItem(pageIndex); @@ -153,7 +128,6 @@ public class ModulesFragment extends Fragment { } - private class updateUI extends AsyncTask { @Override 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 52b74550f..e4616718f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -5,6 +5,7 @@ import android.app.Activity; import android.app.DownloadManager; import android.app.ProgressDialog; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -13,6 +14,7 @@ import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Environment; +import android.provider.DocumentsContract; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; @@ -33,16 +35,18 @@ import org.json.JSONObject; import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import javax.crypto.BadPaddingException; @@ -483,30 +487,106 @@ public class Utils { return null; } - } public static class FlashZIP extends AsyncTask { private String mPath, mName; + private Uri mUri; private ProgressDialog progress; + private File mFile; private Context mContext; private List ret; + private boolean deleteFileAfter; public FlashZIP(Context context, String name, String path) { mContext = context; mName = name; mPath = path; + deleteFileAfter = false; + } + + public FlashZIP(Context context, Uri uRi, int flags) { + mContext = context; + mUri = uRi; + deleteFileAfter = true; + String file = ""; + final String docId = DocumentsContract.getDocumentId(mUri); + + Log.d("Magisk","Utils: FlashZip Running, " + docId + " and " + mUri.toString()); + String[] split = docId.split(":"); + mName = split[1]; + if (mName.contains("/")) { + split = mName.split("/"); + } + if (split[1].contains(".zip")) { + file = mContext.getFilesDir() + "/" + split[1]; + Log.d("Magisk", "Utils: FlashZip running for uRI " + mUri.toString()); + } else { + Log.e("Magisk", "Utils: error parsing Zipfile " + mUri.getPath()); + this.cancel(true); + } + ContentResolver contentResolver = mContext.getContentResolver(); + contentResolver.takePersistableUriPermission(mUri, flags); + try { + InputStream in = contentResolver.openInputStream(mUri); + Log.d("Magisk", "Firing inputStream"); + mFile = createFileFromInputStream(in, file, mContext); + if (mFile != null) { + mPath = mFile.getPath(); + Log.d("Magisk", "Utils: Mpath is " + mPath); + } else { + Log.e("Magisk", "Utils: error creating file " + mUri.getPath()); + this.cancel(true); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + // TODO handle non-primary volumes + + } + + private static File createFileFromInputStream(InputStream inputStream, String fileName, Context context) { + + try { + File f = new File(fileName); + f.setWritable(true, false); + OutputStream outputStream = new FileOutputStream(f); + byte buffer[] = new byte[1024]; + int length; + + while ((length = inputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + + outputStream.close(); + inputStream.close(); + Log.d("Magisk", "Holy balls, I think it worked. File is " + f.getPath()); + return f; + + } catch (IOException e) { + System.out.println("error in creating a file"); + e.printStackTrace(); + } + + return null; } @Override protected void onPreExecute() { super.onPreExecute(); + progress = ProgressDialog.show(mContext, mContext.getString(R.string.zip_install_progress_title), mContext.getString(R.string.zip_install_progress_msg, mName)); } @Override protected Boolean doInBackground(Void... voids) { + if (mPath != null) { + Log.e("Magisk", "Utils: Error, flashZIP called without a valid zip file to flash."); + this.cancel(true); + return false; + } if (!Shell.rootAccess()) { return false; } else { @@ -518,7 +598,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" ); - return Boolean.parseBoolean(ret.get(ret.size() - 1)); + return ret != null && Boolean.parseBoolean(ret.get(ret.size() - 1)); } } @@ -526,6 +606,10 @@ public class Utils { protected void onPostExecute(Boolean result) { super.onPostExecute(result); Shell.su("rm -rf /data/tmp"); + if (deleteFileAfter) { + Shell.su("rm -rf " + mPath); + Log.d("Magisk", "Utils: Deleting file " + mPath); + } progress.dismiss(); if (!result) { Toast.makeText(mContext, mContext.getString(R.string.manual_install, mPath), Toast.LENGTH_LONG).show(); @@ -550,5 +634,4 @@ public class Utils { } - } From 0b02e8116c738a80aac7c55b4dea2da849a1b3b5 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Thu, 15 Sep 2016 12:52:58 -0500 Subject: [PATCH 26/27] Holy tapdancing god, it works now! --- app/src/main/AndroidManifest.xml | 25 ++++++++++++ .../com/topjohnwu/magisk/ModulesFragment.java | 40 ++++++++++++++----- .../com/topjohnwu/magisk/utils/Utils.java | 4 +- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7dd7816f3..64c370b5a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,7 +24,32 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 93110915b..40f932cce 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -2,9 +2,12 @@ package com.topjohnwu.magisk; import android.app.Activity; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.provider.MediaStore; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.TabLayout; @@ -12,13 +15,17 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; +import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; +import android.widget.Toast; +import com.ipaulpro.afilechooser.FileInfo; +import com.ipaulpro.afilechooser.utils.FileUtils; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.RepoHelper; import com.topjohnwu.magisk.utils.Utils; @@ -54,9 +61,10 @@ public class ModulesFragment extends Fragment { ButterKnife.bind(this, view); fabio.setOnClickListener(v -> { - Intent fileIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT); - fileIntent.setType("application/zip"); - fileIntent.addCategory(Intent.CATEGORY_OPENABLE); + Intent getContentIntent = FileUtils.createGetContentIntent(null); + getContentIntent.setType("application/zip"); + Intent fileIntent = Intent.createChooser(getContentIntent, "Select a file"); + startActivityForResult(fileIntent, FETCH_ZIP_CODE); }); @@ -75,13 +83,27 @@ public class ModulesFragment extends Fragment { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - Uri mUri = data.getData(); - final int takeFlags = data.getFlags() - & (Intent.FLAG_GRANT_READ_URI_PERMISSION - | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (resultCode == Activity.RESULT_OK && requestCode == FETCH_ZIP_CODE) { - new Utils.FlashZIP(getActivity(), mUri, takeFlags).execute(); + if (data != null) { + // Get the URI of the selected file + final Uri uri = data.getData(); + Log.i("Magisk", "ModulesFragment: Uri = " + uri.toString() + " or "); + new Utils.FlashZIP(getActivity(),uri).execute(); + try { + // Get the file path from the URI + FileInfo fileInfo = FileUtils.getFileInfo(getActivity(), uri); + Toast.makeText(getActivity(), + "File Selected: " + fileInfo.getDisplayName() + " size: " + fileInfo.getSize(), Toast.LENGTH_LONG).show(); + + if (!fileInfo.isExternal()) { + + } else { + + } + } catch (Exception e) { + Log.e("FileSelectorTestAc...", "File select error", e); + } } + } @Override 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 e4616718f..84957bcc9 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -506,7 +506,7 @@ public class Utils { deleteFileAfter = false; } - public FlashZIP(Context context, Uri uRi, int flags) { + public FlashZIP(Context context, Uri uRi) { mContext = context; mUri = uRi; deleteFileAfter = true; @@ -527,7 +527,7 @@ public class Utils { this.cancel(true); } ContentResolver contentResolver = mContext.getContentResolver(); - contentResolver.takePersistableUriPermission(mUri, flags); + //contentResolver.takePersistableUriPermission(mUri, flags); try { InputStream in = contentResolver.openInputStream(mUri); Log.d("Magisk", "Firing inputStream"); From 339ca7accfce67cfdc811fda657573d5f813c1bc Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Thu, 15 Sep 2016 13:42:33 -0500 Subject: [PATCH 27/27] Run with it, boss... --- app/src/main/res/layout/single_module_fragment.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/layout/single_module_fragment.xml b/app/src/main/res/layout/single_module_fragment.xml index 4b0e9f839..336fbdb93 100644 --- a/app/src/main/res/layout/single_module_fragment.xml +++ b/app/src/main/res/layout/single_module_fragment.xml @@ -12,6 +12,8 @@ android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" + android:clipToPadding="false" + android:paddingBottom="60dip" app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>