From 0dad43cfca92c5425a26fafbcabb354e74165d2f Mon Sep 17 00:00:00 2001 From: M66B Date: Sun, 19 Jul 2020 15:50:24 +0200 Subject: [PATCH] Cached disconnect list --- .../eu/faircode/email/AdapterMessage.java | 35 +----- .../java/eu/faircode/email/ApplicationEx.java | 2 + .../faircode/email/DisconnectBlacklist.java | 119 ++++++++++++------ 3 files changed, 85 insertions(+), 71 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index 55c38b79bf..bf20d5aaef 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -5957,36 +5957,11 @@ public class AdapterMessage extends RecyclerView.Adapter>() { - @Override - protected void onPreExecute(Bundle args) { - tvDisconnect.setVisibility(View.GONE); - tvDisconnectCategories.setVisibility(View.GONE); - } - - @Override - protected List onExecute(Context context, Bundle args) throws Throwable { - Uri uri = args.getParcelable("uri"); - return DisconnectBlacklist.getCategories(uri.getHost(), context); - } - - @Override - protected void onExecuted(Bundle args, List data) { - if (data != null) { - tvDisconnectCategories.setText(TextUtils.join(", ", data)); - tvDisconnect.setVisibility(View.VISIBLE); - tvDisconnectCategories.setVisibility(View.VISIBLE); - } - } - - @Override - protected void onException(Bundle args, Throwable ex) { - Log.unexpectedError(getParentFragmentManager(), ex); - } - }.execute(getContext(), getViewLifecycleOwner(), args, "disconnect"); + List categories = DisconnectBlacklist.getCategories(uri.getHost()); + if (categories != null) + tvDisconnectCategories.setText(TextUtils.join(", ", categories)); + tvDisconnect.setVisibility(categories == null ? View.GONE : View.VISIBLE); + tvDisconnectCategories.setVisibility(categories == null ? View.GONE : View.VISIBLE); final Context context = getContext(); diff --git a/app/src/main/java/eu/faircode/email/ApplicationEx.java b/app/src/main/java/eu/faircode/email/ApplicationEx.java index c79f354991..6561bb2eb2 100644 --- a/app/src/main/java/eu/faircode/email/ApplicationEx.java +++ b/app/src/main/java/eu/faircode/email/ApplicationEx.java @@ -114,6 +114,8 @@ public class ApplicationEx extends Application { MessageHelper.setSystemProperties(this); ContactInfo.init(this); + DisconnectBlacklist.init(this); + WorkerWatchdog.init(this); WorkerCleanup.queue(this); diff --git a/app/src/main/java/eu/faircode/email/DisconnectBlacklist.java b/app/src/main/java/eu/faircode/email/DisconnectBlacklist.java index 3b65452d60..2eeeb8c473 100644 --- a/app/src/main/java/eu/faircode/email/DisconnectBlacklist.java +++ b/app/src/main/java/eu/faircode/email/DisconnectBlacklist.java @@ -21,6 +21,7 @@ package eu.faircode.email; import android.content.Context; import android.net.Uri; +import android.os.SystemClock; import org.json.JSONArray; import org.json.JSONException; @@ -31,15 +32,86 @@ import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ExecutorService; import javax.net.ssl.HttpsURLConnection; public class DisconnectBlacklist { + private static final Map> map = new HashMap<>(); + private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "disconnect"); + private final static int FETCH_TIMEOUT = 20 * 1000; // milliseconds private final static String LIST = "https://raw.githubusercontent.com/disconnectme/disconnect-tracking-protection/master/services.json"; + static void init(Context context) { + final File file = getFile(context); + + executor.submit(new Runnable() { + @Override + public void run() { + try { + init(file); + } catch (Throwable ex) { + Log.e(ex); + } + } + }); + } + + private static void init(File file) throws IOException, JSONException { + synchronized (map) { + long start = SystemClock.elapsedRealtime(); + + map.clear(); + + String json = Helper.readText(file); + JSONObject jdisconnect = new JSONObject(json); + JSONObject jcategories = (JSONObject) jdisconnect.get("categories"); + Iterator categories = jcategories.keys(); + while (categories.hasNext()) { + String category = categories.next(); + JSONArray jcategory = jcategories.getJSONArray(category); + for (int c = 0; c < jcategory.length(); c++) { + JSONObject jblock = (JSONObject) jcategory.get(c); + Iterator names = jblock.keys(); + if (names.hasNext()) { + String name = names.next(); + JSONObject jsites = (JSONObject) jblock.get(name); + Iterator sites = jsites.keys(); + if (sites.hasNext()) { + List domains = new ArrayList<>(); + + String site = sites.next(); + String host = Uri.parse(site).getHost(); + if (host != null) + domains.add(host.toLowerCase(Locale.ROOT)); + + JSONArray jdomains = jsites.getJSONArray(site); + for (int d = 0; d < jdomains.length(); d++) + domains.add(jdomains.getString(d).toLowerCase(Locale.ROOT)); + + for (String domain : domains) { + if (!map.containsKey(domain)) + map.put(domain, new ArrayList<>()); + List list = map.get(domain); + if (!list.contains(category)) + list.add(category); + } + } + } + } + } + + long elapsed = SystemClock.elapsedRealtime() - start; + Log.i("Disconnect domains=" + map.size() + " elapsed=" + elapsed + " ms"); + } + } + static void download(Context context) throws IOException, JSONException { File file = getFile(context); @@ -57,53 +129,18 @@ public class DisconnectBlacklist { } finally { connection.disconnect(); } + + init(file); } - static List getCategories(String domain, Context context) throws IOException, JSONException { + static List getCategories(String domain) { if (domain == null) return null; - File file = getFile(context); - if (!file.exists()) - return null; - - List result = new ArrayList<>(); - - String json = Helper.readText(file); - JSONObject jdisconnect = new JSONObject(json); - JSONObject jcategories = (JSONObject) jdisconnect.get("categories"); - Iterator categories = jcategories.keys(); - while (categories.hasNext()) { - String category = categories.next(); - JSONArray jcategory = jcategories.getJSONArray(category); - for (int c = 0; c < jcategory.length(); c++) { - JSONObject jblock = (JSONObject) jcategory.get(c); - Iterator names = jblock.keys(); - if (names.hasNext()) { - String name = names.next(); - JSONObject jsites = (JSONObject) jblock.get(name); - Iterator sites = jsites.keys(); - if (sites.hasNext()) { - List domains = new ArrayList<>(); - - String site = sites.next(); - String host = Uri.parse(site).getHost(); - if (host != null) - domains.add(host); - - JSONArray jdomains = jsites.getJSONArray(site); - for (int d = 0; d < jdomains.length(); d++) - domains.add(jdomains.getString(d)); - - for (String d : domains) - if (domain.equalsIgnoreCase(d) && !result.contains(category)) - result.add(category); - } - } - } + synchronized (map) { + List result = map.get(domain.toLowerCase(Locale.ROOT)); + return (result == null || result.size() == 0 ? null : result); } - - return (result.size() == 0 ? null : result); } private static File getFile(Context context) {