You've already forked Magisk
mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-09-06 06:36:58 +00:00
Simplify asynchronous tasks
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.topjohnwu.magisk.BuildConfig;
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.utils.NotificationMgr;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
@@ -11,19 +12,9 @@ import com.topjohnwu.magisk.utils.WebService;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
public class CheckUpdates {
|
||||
|
||||
private boolean showNotification;
|
||||
|
||||
public CheckUpdates() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public CheckUpdates(boolean b) {
|
||||
showNotification = b;
|
||||
}
|
||||
|
||||
private int getInt(JSONObject json, String name, int defValue) {
|
||||
private static int getInt(JSONObject json, String name, int defValue) {
|
||||
if (json == null)
|
||||
return defValue;
|
||||
try {
|
||||
@@ -33,7 +24,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
}
|
||||
}
|
||||
|
||||
private String getString(JSONObject json, String name, String defValue) {
|
||||
private static String getString(JSONObject json, String name, String defValue) {
|
||||
if (json == null)
|
||||
return defValue;
|
||||
try {
|
||||
@@ -43,7 +34,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject getJson(JSONObject json, String name) {
|
||||
private static JSONObject getJson(JSONObject json, String name) {
|
||||
try {
|
||||
return json.getJSONObject(name);
|
||||
} catch (JSONException e) {
|
||||
@@ -51,9 +42,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
MagiskManager mm = Data.MM();
|
||||
public static void fetchUpdates() {
|
||||
String jsonStr = "";
|
||||
switch (Data.updateChannel) {
|
||||
case Const.Value.STABLE_CHANNEL:
|
||||
@@ -63,7 +52,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
jsonStr = WebService.getString(Const.Url.BETA_URL);
|
||||
break;
|
||||
case Const.Value.CUSTOM_CHANNEL:
|
||||
jsonStr = WebService.getString(mm.prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
||||
jsonStr = WebService.getString(Data.MM().prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -71,7 +60,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
try {
|
||||
json = new JSONObject(jsonStr);
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
JSONObject magisk = getJson(json, "magisk");
|
||||
@@ -88,20 +77,24 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
JSONObject uninstaller = getJson(json, "uninstaller");
|
||||
Data.uninstallerLink = getString(uninstaller, "link", null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
if (showNotification) {
|
||||
if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) {
|
||||
NotificationMgr.managerUpdate();
|
||||
} else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) {
|
||||
NotificationMgr.magiskUpdate();
|
||||
public static void check(Runnable cb) {
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
fetchUpdates();
|
||||
if (cb != null) {
|
||||
if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) {
|
||||
NotificationMgr.managerUpdate();
|
||||
} else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) {
|
||||
NotificationMgr.magiskUpdate();
|
||||
}
|
||||
cb.run();
|
||||
}
|
||||
}
|
||||
Topic.publish(Topic.UPDATE_CHECK_DONE);
|
||||
super.onPostExecute(v);
|
||||
Topic.publish(Topic.UPDATE_CHECK_DONE);
|
||||
});
|
||||
}
|
||||
|
||||
public static void check() {
|
||||
check(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
|
||||
console.add("! This zip is not a Magisk Module!");
|
||||
break;
|
||||
case 1:
|
||||
// Success
|
||||
new LoadModules().exec();
|
||||
// Reload modules
|
||||
Utils.loadModules();
|
||||
break;
|
||||
}
|
||||
activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.PatchAPK;
|
||||
import com.topjohnwu.magisk.utils.RootUtils;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
import com.topjohnwu.superuser.io.SuFileOutputStream;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class HideManager extends ParallelTask<Void, Void, Boolean> {
|
||||
|
||||
private ProgressDialog dialog;
|
||||
|
||||
public HideManager(Activity activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
private String genPackageName(String prefix, int length) {
|
||||
StringBuilder builder = new StringBuilder(length);
|
||||
builder.append(prefix);
|
||||
length -= prefix.length();
|
||||
SecureRandom random = new SecureRandom();
|
||||
String base = "abcdefghijklmnopqrstuvwxyz";
|
||||
String alpha = base + base.toUpperCase();
|
||||
String full = alpha + "0123456789..........";
|
||||
char next, prev = '\0';
|
||||
for (int i = 0; i < length; ++i) {
|
||||
if (prev == '.' || i == length - 1 || i == 0) {
|
||||
next = alpha.charAt(random.nextInt(alpha.length()));
|
||||
} else {
|
||||
next = full.charAt(random.nextInt(full.length()));
|
||||
}
|
||||
builder.append(next);
|
||||
prev = next;
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
dialog = ProgressDialog.show(getActivity(),
|
||||
getActivity().getString(R.string.hide_manager_toast),
|
||||
getActivity().getString(R.string.hide_manager_toast2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
MagiskManager mm = Data.MM();
|
||||
|
||||
// Generate a new app with random package name
|
||||
SuFile repack = new SuFile("/data/local/tmp/repack.apk");
|
||||
String pkg = genPackageName("com.", Const.ORIG_PKG_NAME.length());
|
||||
|
||||
try {
|
||||
if (!PatchAPK.patchPackageID(
|
||||
mm.getPackageCodePath(),
|
||||
new SuFileOutputStream(repack),
|
||||
Const.ORIG_PKG_NAME, pkg))
|
||||
return false;
|
||||
} catch (FileNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Install the application
|
||||
if (!ShellUtils.fastCmdResult(Shell.getShell(), "pm install " + repack))
|
||||
return false;
|
||||
|
||||
repack.delete();
|
||||
|
||||
mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
|
||||
Data.exportPrefs();
|
||||
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean b) {
|
||||
dialog.dismiss();
|
||||
if (!b) {
|
||||
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
||||
}
|
||||
super.onPostExecute(b);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.container.Module;
|
||||
import com.topjohnwu.magisk.container.ValueSortedMap;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
|
||||
public class LoadModules extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
private String[] getModList() {
|
||||
SuFile path = new SuFile(Const.MAGISK_PATH);
|
||||
return path.list((file, name) -> !name.equals("lost+found") && !name.equals(".core"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
MagiskManager mm = Data.MM();
|
||||
mm.moduleMap = new ValueSortedMap<>();
|
||||
|
||||
for (String name : getModList()) {
|
||||
Module module = new Module(Const.MAGISK_PATH + "/" + name);
|
||||
mm.moduleMap.put(module.getId(), module);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
Topic.publish(Topic.MODULE_LOAD_DONE);
|
||||
super.onPostExecute(v);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.os.AsyncTask;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.RootUtils;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
import com.topjohnwu.superuser.io.SuFileOutputStream;
|
||||
import com.topjohnwu.utils.JarMap;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
public class PatchAPK {
|
||||
|
||||
private static String genPackageName(String prefix, int length) {
|
||||
StringBuilder builder = new StringBuilder(length);
|
||||
builder.append(prefix);
|
||||
length -= prefix.length();
|
||||
SecureRandom random = new SecureRandom();
|
||||
String base = "abcdefghijklmnopqrstuvwxyz";
|
||||
String alpha = base + base.toUpperCase();
|
||||
String full = alpha + "0123456789..........";
|
||||
char next, prev = '\0';
|
||||
for (int i = 0; i < length; ++i) {
|
||||
if (prev == '.' || i == length - 1 || i == 0) {
|
||||
next = alpha.charAt(random.nextInt(alpha.length()));
|
||||
} else {
|
||||
next = full.charAt(random.nextInt(full.length()));
|
||||
}
|
||||
builder.append(next);
|
||||
prev = next;
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static int findOffset(byte buf[], byte pattern[]) {
|
||||
int offset = -1;
|
||||
for (int i = 0; i < buf.length - pattern.length; ++i) {
|
||||
boolean match = true;
|
||||
for (int j = 0; j < pattern.length; ++j) {
|
||||
if (buf[i + j] != pattern[j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
offset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* It seems that AAPT sometimes generate another type of string format */
|
||||
private static boolean fallbackPatch(byte xml[], String from, String to) {
|
||||
|
||||
byte[] target = new byte[from.length() * 2 + 2];
|
||||
for (int i = 0; i < from.length(); ++i) {
|
||||
target[i * 2] = (byte) from.charAt(i);
|
||||
}
|
||||
int offset = findOffset(xml, target);
|
||||
if (offset < 0)
|
||||
return false;
|
||||
byte[] dest = new byte[target.length - 2];
|
||||
for (int i = 0; i < to.length(); ++i) {
|
||||
dest[i * 2] = (byte) to.charAt(i);
|
||||
}
|
||||
System.arraycopy(dest, 0, xml, offset, dest.length);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean findAndPatch(byte xml[], String from, String to) {
|
||||
byte target[] = (from + '\0').getBytes();
|
||||
int offset = findOffset(xml, target);
|
||||
if (offset < 0)
|
||||
return fallbackPatch(xml, from, to);
|
||||
System.arraycopy(to.getBytes(), 0, xml, offset, to.length());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean patchAndHide() {
|
||||
MagiskManager mm = Data.MM();
|
||||
|
||||
// Generate a new app with random package name
|
||||
SuFile repack = new SuFile("/data/local/tmp/repack.apk");
|
||||
String pkg = genPackageName("com.", Const.ORIG_PKG_NAME.length());
|
||||
|
||||
try {
|
||||
JarMap apk = new JarMap(mm.getPackageCodePath());
|
||||
if (!patchPackageID(apk, Const.ORIG_PKG_NAME, pkg))
|
||||
return false;
|
||||
ZipUtils.signZip(apk, new SuFileOutputStream(repack));
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Install the application
|
||||
if (!ShellUtils.fastCmdResult("pm install " + repack))
|
||||
return false;
|
||||
|
||||
repack.delete();
|
||||
|
||||
mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
|
||||
Data.exportPrefs();
|
||||
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean patchPackageID(JarMap apk, String from, String to) {
|
||||
try {
|
||||
JarEntry je = apk.getJarEntry(Const.ANDROID_MANIFEST);
|
||||
byte xml[] = apk.getRawData(je);
|
||||
|
||||
if (!findAndPatch(xml, from, to))
|
||||
return false;
|
||||
if (!findAndPatch(xml, from + ".provider", to + ".provider"))
|
||||
return false;
|
||||
|
||||
// Write in changes
|
||||
apk.getOutputStream(je).write(xml);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void hideManager(Activity activity) {
|
||||
ProgressDialog dialog = ProgressDialog.show(activity,
|
||||
activity.getString(R.string.hide_manager_toast),
|
||||
activity.getString(R.string.hide_manager_toast2));
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
boolean b = patchAndHide();
|
||||
Data.mainHandler.post(() -> {
|
||||
dialog.cancel();
|
||||
if (!b) {
|
||||
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
|
||||
public class RestoreImages extends ParallelTask<Void, Void, Boolean> {
|
||||
|
||||
private ProgressDialog dialog;
|
||||
|
||||
public RestoreImages(Activity activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
Activity a = getActivity();
|
||||
dialog = ProgressDialog.show(a, a.getString(R.string.restore_img), a.getString(R.string.restore_img_msg));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
return ShellUtils.fastCmdResult("restore_imgs");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
dialog.cancel();
|
||||
if (result) {
|
||||
Utils.toast(R.string.restore_done, Toast.LENGTH_SHORT);
|
||||
} else {
|
||||
Utils.toast(R.string.restore_fail, Toast.LENGTH_LONG);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
@@ -34,7 +35,7 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
||||
public class UpdateRepos {
|
||||
|
||||
private static final int CHECK_ETAG = 0;
|
||||
private static final int LOAD_NEXT = 1;
|
||||
@@ -44,16 +45,14 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
||||
private static final int CORE_POOL_SIZE = Math.max(2, CPU_COUNT - 1);
|
||||
|
||||
private MagiskManager mm;
|
||||
private List<String> etags, newEtags = new LinkedList<>();
|
||||
private List<String> etags, newEtags;
|
||||
private Set<String> cached;
|
||||
private boolean forceUpdate;
|
||||
private ExecutorService threadPool;
|
||||
|
||||
public UpdateRepos(boolean force) {
|
||||
Topic.reset(Topic.REPO_LOAD_DONE);
|
||||
public UpdateRepos() {
|
||||
mm = Data.MM();
|
||||
forceUpdate = force;
|
||||
threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
|
||||
newEtags = new LinkedList<>();
|
||||
}
|
||||
|
||||
private void waitTasks() {
|
||||
@@ -85,7 +84,10 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
||||
set.remove(id);
|
||||
repo.update(date);
|
||||
mm.repoDB.addRepo(repo);
|
||||
publishProgress();
|
||||
Data.mainHandler.post(() -> {
|
||||
if (ReposFragment.adapter != null)
|
||||
ReposFragment.adapter.notifyDBChanged();
|
||||
});
|
||||
} catch (Repo.IllegalRepoException e) {
|
||||
Logger.debug(e.getMessage());
|
||||
mm.repoDB.removeRepo(id);
|
||||
@@ -142,47 +144,45 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Void... values) {
|
||||
if (ReposFragment.adapter != null)
|
||||
ReposFragment.adapter.notifyDBChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
etags = Arrays.asList(mm.prefs.getString(Const.Key.ETAG_KEY, "").split(","));
|
||||
cached = mm.repoDB.getRepoIDSet();
|
||||
|
||||
if (loadPage(0, CHECK_ETAG)) {
|
||||
waitTasks();
|
||||
|
||||
// The leftover cached means they are removed from online repo
|
||||
mm.repoDB.removeRepo(cached);
|
||||
|
||||
// Update ETag
|
||||
mm.prefs.edit().putString(Const.Key.ETAG_KEY, TextUtils.join(",", newEtags)).apply();
|
||||
} else if (forceUpdate) {
|
||||
Cursor c = mm.repoDB.getRawCursor();
|
||||
while (c.moveToNext()) {
|
||||
Repo repo = new Repo(c);
|
||||
threadPool.execute(() -> {
|
||||
try {
|
||||
repo.update();
|
||||
mm.repoDB.addRepo(repo);
|
||||
} catch (Repo.IllegalRepoException e) {
|
||||
Logger.debug(e.getMessage());
|
||||
mm.repoDB.removeRepo(repo);
|
||||
}
|
||||
});
|
||||
}
|
||||
waitTasks();
|
||||
private void fullReload() {
|
||||
Cursor c = mm.repoDB.getRawCursor();
|
||||
while (c.moveToNext()) {
|
||||
Repo repo = new Repo(c);
|
||||
threadPool.execute(() -> {
|
||||
try {
|
||||
repo.update();
|
||||
mm.repoDB.addRepo(repo);
|
||||
} catch (Repo.IllegalRepoException e) {
|
||||
Logger.debug(e.getMessage());
|
||||
mm.repoDB.removeRepo(repo);
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
waitTasks();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
Topic.publish(Topic.REPO_LOAD_DONE);
|
||||
super.onPostExecute(v);
|
||||
public void exec(boolean force) {
|
||||
Topic.reset(Topic.REPO_LOAD_DONE);
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
etags = Arrays.asList(mm.prefs.getString(Const.Key.ETAG_KEY, "").split(","));
|
||||
cached = mm.repoDB.getRepoIDSet();
|
||||
|
||||
if (loadPage(0, CHECK_ETAG)) {
|
||||
waitTasks();
|
||||
|
||||
// The leftover cached means they are removed from online repo
|
||||
mm.repoDB.removeRepo(cached);
|
||||
|
||||
// Update ETag
|
||||
mm.prefs.edit().putString(Const.Key.ETAG_KEY, TextUtils.join(",", newEtags)).apply();
|
||||
} else if (force) {
|
||||
fullReload();
|
||||
}
|
||||
Topic.publish(Topic.REPO_LOAD_DONE);
|
||||
});
|
||||
}
|
||||
|
||||
public void exec() {
|
||||
exec(false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user