Skip to content

Commit

Permalink
Remove GSON and switch to database
Browse files Browse the repository at this point in the history
  • Loading branch information
topjohnwu committed Feb 12, 2017
1 parent 1418ec2 commit 44b0d41
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 89 deletions.
2 changes: 0 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ dependencies {
compile 'com.android.support:cardview-v7:25.1.1'
compile 'com.android.support:design:25.1.1'
compile 'com.android.support:support-v4:25.1.1'
compile 'com.android.support:support-v13:25.1.1'
compile 'com.jakewharton:butterknife:8.5.1'
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.github.clans:fab:1.6.4'
compile 'com.thoughtbot:expandablerecyclerview:1.4'
compile 'com.madgag.spongycastle:core:1.54.0.0'
Expand Down
21 changes: 0 additions & 21 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,6 @@
# public *;
#}

# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.topjohnwu.magisk.module.** { *; }
-keep class com.topjohnwu.magisk.module.ModuleHelper$ValueSortedMap { *; }

# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

-keep class android.support.v7.internal.** { *; }
-keep interface android.support.v7.internal.** { *; }
-keep class android.support.v7.** { *; }
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/topjohnwu/magisk/SuLogFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import com.topjohnwu.magisk.adapters.SuLogAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.superuser.SuLogDatabaseHelper;
import com.topjohnwu.magisk.database.SuLogDatabaseHelper;
import com.topjohnwu.magisk.superuser.SuLogEntry;

import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

import com.topjohnwu.magisk.adapters.PolicyAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.superuser.SuDatabaseHelper;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import android.widget.TextView;

import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.superuser.SuDatabaseHelper;
import com.topjohnwu.magisk.utils.Utils;

import java.util.HashSet;
Expand Down
77 changes: 35 additions & 42 deletions app/src/main/java/com/topjohnwu/magisk/asyncs/LoadRepos.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

import android.app.Activity;
import android.content.SharedPreferences;
import android.text.TextUtils;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.module.BaseModule;
import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.utils.Logger;
Expand All @@ -16,6 +15,7 @@
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
Expand All @@ -26,13 +26,14 @@
public class LoadRepos extends ParallelTask<Void, Void, Void> {

public static final String ETAG_KEY = "ETag";
public static final String VERSION_KEY = "version";
public static final String REPO_KEY = "repomap";
public static final String FILE_KEY = "RepoMap";
private static final int GSON_DB_VER = 1;

private static final String REPO_URL = "https://api.github.com/orgs/Magisk-Modules-Repo/repos";

private String prefsPath;

public LoadRepos(Activity context) {
super(context);
prefsPath = context.getApplicationInfo().dataDir + "/shared_prefs";
}

@Override
Expand All @@ -41,39 +42,27 @@ protected Void doInBackground(Void... voids) {

SharedPreferences prefs = magiskManager.prefs;

magiskManager.repoMap = new ValueSortedMap<>();
// Legacy data cleanup
new File(prefsPath, "RepoMap.xml").delete();
prefs.edit().remove("version").remove("repomap").apply();

Gson gson = new Gson();
String jsonString;

int cachedVersion = prefs.getInt(VERSION_KEY, 0);
if (cachedVersion != GSON_DB_VER) {
// Ignore incompatible cached database
jsonString = null;
} else {
jsonString = prefs.getString(REPO_KEY, null);
}

Map<String, Repo> cached = null;
Map<String, String> header = new HashMap<>();
// Get cached ETag to add in the request header
String etag = prefs.getString(ETAG_KEY, "");

if (jsonString != null) {
cached = gson.fromJson(jsonString, new TypeToken<ValueSortedMap<String, Repo>>(){}.getType());
}
// Add header only if db exists
if (magiskManager.getDatabasePath("repo.db").exists())
header.put("If-None-Match", etag);

if (cached == null) {
cached = new ValueSortedMap<>();
}
magiskManager.repoMap = new ValueSortedMap<>();

// Get cached ETag to add in the request header
String etag = prefs.getString(ETAG_KEY, "");
Map<String, String> header = new HashMap<>();
header.put("If-None-Match", etag);
// Make a request to main URL for repo info
String jsonString = WebService.request(REPO_URL, WebService.GET, null, header, false);

// Making a request to main URL for repo info
jsonString = WebService.request(
magiskManager.getString(R.string.url_main), WebService.GET, null, header, false);
RepoDatabaseHelper dbHelper = new RepoDatabaseHelper(magiskManager);
ValueSortedMap<String, Repo> cached = dbHelper.getRepoMap();

if (!jsonString.isEmpty()) {
if (!TextUtils.isEmpty(jsonString)) {
try {
JSONArray jsonArray = new JSONArray(jsonString);
// If it gets to this point, the response is valid, update ETag
Expand All @@ -98,30 +87,34 @@ protected Void doInBackground(Void... voids) {
try {
if (repo == null) {
Logger.dev("LoadRepos: Create new repo " + id);
repo = new Repo(magiskManager, name, updatedDate);
repo = new Repo(name, updatedDate);
} else {
// Popout from cached
cached.remove(id);
Logger.dev("LoadRepos: Update cached repo " + id);
repo.update(updatedDate);
}
if (repo.getId() != null) {
if (repo.getId() != null)
magiskManager.repoMap.put(id, repo);
}
} catch (BaseModule.CacheModException ignored) {}
}

} catch (JSONException e) {
e.printStackTrace();
}
} else {
// Use cached if no internet or no updates
Logger.dev("LoadRepos: No updates, use cached");
magiskManager.repoMap.putAll(cached);
cached.clear();
}

prefs.edit()
.putInt(VERSION_KEY, GSON_DB_VER)
.putString(REPO_KEY, gson.toJson(magiskManager.repoMap))
.putString(ETAG_KEY, etag)
.apply();
// Update the database
dbHelper.addRepoMap(magiskManager.repoMap);
// The leftover cached are those removed remote, cleanup db
dbHelper.removeRepo(cached);
// Update ETag
prefs.edit().putString(ETAG_KEY, etag).apply();

Logger.dev("LoadRepos: Repo load done");
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.topjohnwu.magisk.database;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.utils.ValueSortedMap;

import java.util.Collection;

public class RepoDatabaseHelper extends SQLiteOpenHelper {

private static final int DATABASE_VER = 1;
private static final String TABLE_NAME = "repos";

public RepoDatabaseHelper(Context context) {
super(context, "repo.db", null, DATABASE_VER);
}

@Override
public void onCreate(SQLiteDatabase db) {
onUpgrade(db, 0, DATABASE_VER);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 0) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " +
"(id TEXT, name TEXT, version TEXT, versionCode INT, " +
"author TEXT, description TEXT, repo_name TEXT, last_update INT, " +
"PRIMARY KEY(id))");
}
// No upgrades yet
}

public void addRepoMap(ValueSortedMap<String, Repo> map) {
SQLiteDatabase db = getWritableDatabase();
Collection<Repo> list = map.values();
for (Repo repo : list)
db.replace(TABLE_NAME, null, repo.getContentValues());
db.close();
}

public void clearRepo() {
SQLiteDatabase db = getWritableDatabase();
db.delete(TABLE_NAME, null, null);
db.close();
}

public void removeRepo(ValueSortedMap<String, Repo> map) {
SQLiteDatabase db = getWritableDatabase();
Collection<Repo> list = map.values();
for (Repo repo : list)
db.delete(TABLE_NAME, "id=?", new String[] { repo.getId() });
db.close();
}

public ValueSortedMap<String, Repo> getRepoMap() {
ValueSortedMap<String, Repo> ret = new ValueSortedMap<>();
SQLiteDatabase db = getReadableDatabase();
Repo repo;
try (Cursor c = db.query(TABLE_NAME, null, null, null, null, null, null)) {
while (c.moveToNext()) {
repo = new Repo(c);
ret.put(repo.getId(), repo);
}
}
db.close();
return ret;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.topjohnwu.magisk.superuser;
package com.topjohnwu.magisk.database;

import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.topjohnwu.magisk.superuser.Policy;

import java.util.ArrayList;
import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.topjohnwu.magisk.superuser;
package com.topjohnwu.magisk.database;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.superuser.SuLogEntry;

import java.util.ArrayList;
import java.util.List;
Expand Down
50 changes: 38 additions & 12 deletions app/src/main/java/com/topjohnwu/magisk/module/Repo.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
package com.topjohnwu.magisk.module;

import android.content.Context;
import android.content.ContentValues;
import android.database.Cursor;

import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.WebService;

import java.util.Date;

public class Repo extends BaseModule {
private String mLogUrl, mManifestUrl, mZipUrl;

private static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s";
private static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip";

private String repoName;
private Date mLastUpdate;

public Repo(Context context, String name, Date lastUpdate) throws CacheModException {
public Repo(String name, Date lastUpdate) throws CacheModException {
mLastUpdate = lastUpdate;
mLogUrl = context.getString(R.string.file_url, name, "changelog.txt");
mManifestUrl = context.getString(R.string.file_url, name, "module.prop");
mZipUrl = context.getString(R.string.zip_url, name);
repoName = name;
update();
}

public Repo(Cursor c) {
mId = c.getString(c.getColumnIndex("id"));
mName = c.getString(c.getColumnIndex("name"));
mVersion = c.getString(c.getColumnIndex("version"));
mVersionCode = c.getInt(c.getColumnIndex("versionCode"));
mAuthor = c.getString(c.getColumnIndex("author"));
mDescription = c.getString(c.getColumnIndex("description"));
repoName = c.getString(c.getColumnIndex("repo_name"));
mLastUpdate = new Date(c.getLong(c.getColumnIndex("last_update")));
}

public void update() throws CacheModException {
Logger.dev("Repo: Re-fetch prop");
String props = WebService.request(mManifestUrl, WebService.GET, true);
String props = WebService.request(getManifestUrl(), WebService.GET, true);
String lines[] = props.split("\\n");
parseProps(lines);
}

public void update(Date lastUpdate) throws CacheModException {
Logger.dev("Repo: Old: " + mLastUpdate + " New: " + lastUpdate);
Logger.dev("Repo: Local: " + mLastUpdate + " Remote: " + lastUpdate);
if (mIsCacheModule)
throw new CacheModException(mId);
if (lastUpdate.after(mLastUpdate)) {
Expand All @@ -37,16 +50,29 @@ public void update(Date lastUpdate) throws CacheModException {
}
}

public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("id", mId);
values.put("name", mName);
values.put("version", mVersion);
values.put("versionCode", mVersionCode);
values.put("author", mAuthor);
values.put("description", mDescription);
values.put("repo_name", repoName);
values.put("last_update", mLastUpdate.getTime());
return values;
}

public String getZipUrl() {
return mZipUrl;
return String.format(ZIP_URL, repoName);
}

public String getLogUrl() {
return mLogUrl;
return String.format(FILE_URL, repoName, "changelog.txt");
}

public String getManifestUrl() {
return mManifestUrl;
return String.format(FILE_URL, repoName, "module.prop");
}

public Date getLastUpdate() {
Expand Down
Loading

0 comments on commit 44b0d41

Please sign in to comment.