| OLD | NEW |
| 1 /* | 1 /* |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
| 4 * | 4 * |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
| 7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
| 8 * | 8 * |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 import android.webkit.WebResourceRequest; // makes android min version to be 21 | 42 import android.webkit.WebResourceRequest; // makes android min version to be 21 |
| 43 import android.webkit.WebResourceResponse; | 43 import android.webkit.WebResourceResponse; |
| 44 import android.webkit.WebStorage; | 44 import android.webkit.WebStorage; |
| 45 import android.webkit.WebView; | 45 import android.webkit.WebView; |
| 46 import android.webkit.WebViewClient; | 46 import android.webkit.WebViewClient; |
| 47 | 47 |
| 48 import org.adblockplus.libadblockplus.FilterEngine; | 48 import org.adblockplus.libadblockplus.FilterEngine; |
| 49 import org.adblockplus.libadblockplus.Subscription; | 49 import org.adblockplus.libadblockplus.Subscription; |
| 50 import org.adblockplus.libadblockplus.android.AdblockEngine; | 50 import org.adblockplus.libadblockplus.android.AdblockEngine; |
| 51 import org.adblockplus.libadblockplus.android.AdblockEngineProvider; | 51 import org.adblockplus.libadblockplus.android.AdblockEngineProvider; |
| 52 import org.adblockplus.libadblockplus.android.SingletonEngineProvider; | 52 import org.adblockplus.libadblockplus.android.SingleInstanceEngineProvider; |
| 53 import org.adblockplus.libadblockplus.android.Utils; | 53 import org.adblockplus.libadblockplus.android.Utils; |
| 54 | 54 |
| 55 import java.io.IOException; | 55 import java.io.IOException; |
| 56 import java.util.Collections; | 56 import java.util.Collections; |
| 57 import java.util.HashMap; | 57 import java.util.HashMap; |
| 58 import java.util.List; | 58 import java.util.List; |
| 59 import java.util.Map; | 59 import java.util.Map; |
| 60 import java.util.concurrent.CountDownLatch; | 60 import java.util.concurrent.CountDownLatch; |
| 61 import java.util.concurrent.atomic.AtomicBoolean; | 61 import java.util.concurrent.atomic.AtomicBoolean; |
| 62 import java.util.regex.Pattern; | 62 import java.util.regex.Pattern; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 90 | 90 |
| 91 private static final Pattern RE_JS = Pattern.compile("\\.js$", Pattern.CASE_IN
SENSITIVE); | 91 private static final Pattern RE_JS = Pattern.compile("\\.js$", Pattern.CASE_IN
SENSITIVE); |
| 92 private static final Pattern RE_CSS = Pattern.compile("\\.css$", Pattern.CASE_
INSENSITIVE); | 92 private static final Pattern RE_CSS = Pattern.compile("\\.css$", Pattern.CASE_
INSENSITIVE); |
| 93 private static final Pattern RE_IMAGE = Pattern.compile("\\.(?:gif|png|jpe?g|b
mp|ico)$", Pattern.CASE_INSENSITIVE); | 93 private static final Pattern RE_IMAGE = Pattern.compile("\\.(?:gif|png|jpe?g|b
mp|ico)$", Pattern.CASE_INSENSITIVE); |
| 94 private static final Pattern RE_FONT = Pattern.compile("\\.(?:ttf|woff)$", Pat
tern.CASE_INSENSITIVE); | 94 private static final Pattern RE_FONT = Pattern.compile("\\.(?:ttf|woff)$", Pat
tern.CASE_INSENSITIVE); |
| 95 private static final Pattern RE_HTML = Pattern.compile("\\.html?$", Pattern.CA
SE_INSENSITIVE); | 95 private static final Pattern RE_HTML = Pattern.compile("\\.html?$", Pattern.CA
SE_INSENSITIVE); |
| 96 | 96 |
| 97 private volatile boolean addDomListener = true; | 97 private volatile boolean addDomListener = true; |
| 98 private boolean adblockEnabled = true; | 98 private boolean adblockEnabled = true; |
| 99 private boolean debugMode; | 99 private boolean debugMode; |
| 100 private AdblockEngineProvider adblockEngineProvider; | 100 private AdblockEngineProvider provider; |
| 101 private Integer loadError; | 101 private Integer loadError; |
| 102 private int allowDrawDelay = ALLOW_DRAW_DELAY; | 102 private int allowDrawDelay = ALLOW_DRAW_DELAY; |
| 103 private WebChromeClient extWebChromeClient; | 103 private WebChromeClient extWebChromeClient; |
| 104 private WebViewClient extWebViewClient; | 104 private WebViewClient extWebViewClient; |
| 105 private WebViewClient intWebViewClient; | 105 private WebViewClient intWebViewClient; |
| 106 private Map<String, String> url2Referrer = Collections.synchronizedMap(new Has
hMap<String, String>()); | 106 private Map<String, String> url2Referrer = Collections.synchronizedMap(new Has
hMap<String, String>()); |
| 107 private String url; | 107 private String url; |
| 108 private String domain; | 108 private String domain; |
| 109 private String injectJs; | 109 private String injectJs; |
| 110 private CountDownLatch elemHideLatch; | 110 private CountDownLatch elemHideLatch; |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 .replace(DEBUG_TOKEN, (debugMode ? "" : "//")); | 227 .replace(DEBUG_TOKEN, (debugMode ? "" : "//")); |
| 228 } | 228 } |
| 229 | 229 |
| 230 private void runScript(String script) | 230 private void runScript(String script) |
| 231 { | 231 { |
| 232 d("runScript started"); | 232 d("runScript started"); |
| 233 evaluateJavascript(script, null); | 233 evaluateJavascript(script, null); |
| 234 d("runScript finished"); | 234 d("runScript finished"); |
| 235 } | 235 } |
| 236 | 236 |
| 237 public void setAdblockEngineProvider(final AdblockEngineProvider adblockEngine
Provider) | 237 public void setProvider(final AdblockEngineProvider provider) |
| 238 { | 238 { |
| 239 if (this.adblockEngineProvider != null && adblockEngineProvider != null && t
his.adblockEngineProvider == adblockEngineProvider) | 239 if (this.provider != null && provider != null && this.provider == provider) |
| 240 { | 240 { |
| 241 return; | 241 return; |
| 242 } | 242 } |
| 243 | 243 |
| 244 final Runnable setRunnable = new Runnable() | 244 final Runnable setRunnable = new Runnable() |
| 245 { | 245 { |
| 246 @Override | 246 @Override |
| 247 public void run() | 247 public void run() |
| 248 { | 248 { |
| 249 AdblockWebView.this.adblockEngineProvider = adblockEngineProvider; | 249 AdblockWebView.this.provider = provider; |
| 250 AdblockWebView.this.adblockEngineProvider.retain(true); // asynchronousl
y | 250 AdblockWebView.this.provider.retain(true); // asynchronously |
| 251 } | 251 } |
| 252 }; | 252 }; |
| 253 | 253 |
| 254 if (this.adblockEngineProvider != null) | 254 if (this.provider != null) |
| 255 { | 255 { |
| 256 // as adblockEngine can be busy with elemhide thread we need to use callba
ck | 256 // as adblockEngine can be busy with elemhide thread we need to use callba
ck |
| 257 this.dispose(setRunnable); | 257 this.dispose(setRunnable); |
| 258 } | 258 } |
| 259 else | 259 else |
| 260 { | 260 { |
| 261 setRunnable.run(); | 261 setRunnable.run(); |
| 262 } | 262 } |
| 263 } | 263 } |
| 264 | 264 |
| (...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 810 { | 810 { |
| 811 super.onReceivedLoginRequest(view, realm, account, args); | 811 super.onReceivedLoginRequest(view, realm, account, args); |
| 812 } | 812 } |
| 813 } | 813 } |
| 814 | 814 |
| 815 protected WebResourceResponse shouldInterceptRequest( | 815 protected WebResourceResponse shouldInterceptRequest( |
| 816 WebView webview, String url, boolean isMainFrame, | 816 WebView webview, String url, boolean isMainFrame, |
| 817 boolean isXmlHttpRequest, String[] referrerChainArray) | 817 boolean isXmlHttpRequest, String[] referrerChainArray) |
| 818 { | 818 { |
| 819 // if dispose() was invoke, but the page is still loading then just let it
go | 819 // if dispose() was invoke, but the page is still loading then just let it
go |
| 820 if (adblockEngineProvider.getAdblockEngine() == null) | 820 if (provider.getCounter() == 0) |
| 821 { | 821 { |
| 822 e("FilterEngine already disposed, allow loading"); | 822 e("FilterEngine already disposed, allow loading"); |
| 823 | 823 |
| 824 // allow loading by returning null | 824 // allow loading by returning null |
| 825 return null; | 825 return null; |
| 826 } | 826 } |
| 827 | 827 |
| 828 if (isMainFrame) | 828 if (isMainFrame) |
| 829 { | 829 { |
| 830 // never blocking main frame requests, just subrequests | 830 // never blocking main frame requests, just subrequests |
| 831 w(url + " is main frame, allow loading"); | 831 w(url + " is main frame, allow loading"); |
| 832 | 832 |
| 833 // allow loading by returning null | 833 // allow loading by returning null |
| 834 return null; | 834 return null; |
| 835 } | 835 } |
| 836 | 836 |
| 837 // whitelisted | 837 // whitelisted |
| 838 if (adblockEngineProvider.getAdblockEngine().isDomainWhitelisted(url, refe
rrerChainArray)) | 838 if (provider.getEngine().isDomainWhitelisted(url, referrerChainArray)) |
| 839 { | 839 { |
| 840 w(url + " domain is whitelisted, allow loading"); | 840 w(url + " domain is whitelisted, allow loading"); |
| 841 | 841 |
| 842 // allow loading by returning null | 842 // allow loading by returning null |
| 843 return null; | 843 return null; |
| 844 } | 844 } |
| 845 | 845 |
| 846 if (adblockEngineProvider.getAdblockEngine().isDocumentWhitelisted(url, re
ferrerChainArray)) | 846 if (provider.getEngine().isDocumentWhitelisted(url, referrerChainArray)) |
| 847 { | 847 { |
| 848 w(url + " document is whitelisted, allow loading"); | 848 w(url + " document is whitelisted, allow loading"); |
| 849 | 849 |
| 850 // allow loading by returning null | 850 // allow loading by returning null |
| 851 return null; | 851 return null; |
| 852 } | 852 } |
| 853 | 853 |
| 854 // determine the content | 854 // determine the content |
| 855 FilterEngine.ContentType contentType; | 855 FilterEngine.ContentType contentType; |
| 856 if (isXmlHttpRequest) | 856 if (isXmlHttpRequest) |
| (...skipping 22 matching lines...) Expand all Loading... |
| 879 { | 879 { |
| 880 contentType = FilterEngine.ContentType.SUBDOCUMENT; | 880 contentType = FilterEngine.ContentType.SUBDOCUMENT; |
| 881 } | 881 } |
| 882 else | 882 else |
| 883 { | 883 { |
| 884 contentType = FilterEngine.ContentType.OTHER; | 884 contentType = FilterEngine.ContentType.OTHER; |
| 885 } | 885 } |
| 886 } | 886 } |
| 887 | 887 |
| 888 // check if we should block | 888 // check if we should block |
| 889 if (adblockEngineProvider.getAdblockEngine().matches(url, contentType, ref
errerChainArray)) | 889 if (provider.getEngine().matches(url, contentType, referrerChainArray)) |
| 890 { | 890 { |
| 891 w("Blocked loading " + url); | 891 w("Blocked loading " + url); |
| 892 | 892 |
| 893 // if we should block, return empty response which results in 'errorLoad
ing' callback | 893 // if we should block, return empty response which results in 'errorLoad
ing' callback |
| 894 return new WebResourceResponse("text/plain", "UTF-8", null); | 894 return new WebResourceResponse("text/plain", "UTF-8", null); |
| 895 } | 895 } |
| 896 | 896 |
| 897 d("Allowed loading " + url); | 897 d("Allowed loading " + url); |
| 898 | 898 |
| 899 // continue by returning null | 899 // continue by returning null |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 958 { | 958 { |
| 959 this.finishedLatch = finishedLatch; | 959 this.finishedLatch = finishedLatch; |
| 960 isCancelled = new AtomicBoolean(false); | 960 isCancelled = new AtomicBoolean(false); |
| 961 } | 961 } |
| 962 | 962 |
| 963 @Override | 963 @Override |
| 964 public void run() | 964 public void run() |
| 965 { | 965 { |
| 966 try | 966 try |
| 967 { | 967 { |
| 968 if (adblockEngineProvider.getAdblockEngine() == null) | 968 if (provider.getCounter() == 0) |
| 969 { | 969 { |
| 970 w("FilterEngine already disposed"); | 970 w("FilterEngine already disposed"); |
| 971 selectorsString = EMPTY_ELEMHIDE_ARRAY_STRING; | 971 selectorsString = EMPTY_ELEMHIDE_ARRAY_STRING; |
| 972 } | 972 } |
| 973 else | 973 else |
| 974 { | 974 { |
| 975 String[] referrers = new String[] | 975 String[] referrers = new String[] |
| 976 { | 976 { |
| 977 url | 977 url |
| 978 }; | 978 }; |
| 979 | 979 |
| 980 List<Subscription> subscriptions = adblockEngineProvider | 980 List<Subscription> subscriptions = provider |
| 981 .getAdblockEngine() | 981 .getEngine() |
| 982 .getFilterEngine() | 982 .getFilterEngine() |
| 983 .getListedSubscriptions(); | 983 .getListedSubscriptions(); |
| 984 | 984 |
| 985 try | 985 try |
| 986 { | 986 { |
| 987 d("Listed subscriptions: " + subscriptions.size()); | 987 d("Listed subscriptions: " + subscriptions.size()); |
| 988 if (debugMode) | 988 if (debugMode) |
| 989 { | 989 { |
| 990 for (Subscription eachSubscription : subscriptions) | 990 for (Subscription eachSubscription : subscriptions) |
| 991 { | 991 { |
| 992 d("Subscribed to " | 992 d("Subscribed to " |
| 993 + (eachSubscription.isDisabled() ? "disabled" : "enabled") | 993 + (eachSubscription.isDisabled() ? "disabled" : "enabled") |
| 994 + " " + eachSubscription); | 994 + " " + eachSubscription); |
| 995 } | 995 } |
| 996 } | 996 } |
| 997 } | 997 } |
| 998 finally | 998 finally |
| 999 { | 999 { |
| 1000 for (Subscription eachSubscription : subscriptions) | 1000 for (Subscription eachSubscription : subscriptions) |
| 1001 { | 1001 { |
| 1002 eachSubscription.dispose(); | 1002 eachSubscription.dispose(); |
| 1003 } | 1003 } |
| 1004 } | 1004 } |
| 1005 | 1005 |
| 1006 d("Requesting elemhide selectors from AdblockEngine for " + url + " in
" + this); | 1006 d("Requesting elemhide selectors from AdblockEngine for " + url + " in
" + this); |
| 1007 List<String> selectors = adblockEngineProvider | 1007 List<String> selectors = provider |
| 1008 .getAdblockEngine() | 1008 .getEngine() |
| 1009 .getElementHidingSelectors(url, domain, referrers); | 1009 .getElementHidingSelectors(url, domain, referrers); |
| 1010 | 1010 |
| 1011 d("Finished requesting elemhide selectors, got " + selectors.size() +
" in " + this); | 1011 d("Finished requesting elemhide selectors, got " + selectors.size() +
" in " + this); |
| 1012 selectorsString = Utils.stringListToJsonArray(selectors); | 1012 selectorsString = Utils.stringListToJsonArray(selectors); |
| 1013 } | 1013 } |
| 1014 } | 1014 } |
| 1015 finally | 1015 finally |
| 1016 { | 1016 { |
| 1017 if (!isCancelled.get()) | 1017 if (!isCancelled.get()) |
| 1018 { | 1018 { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1074 w("elemHideThread set to null"); | 1074 w("elemHideThread set to null"); |
| 1075 elemHideThread = null; | 1075 elemHideThread = null; |
| 1076 } | 1076 } |
| 1077 } | 1077 } |
| 1078 }; | 1078 }; |
| 1079 | 1079 |
| 1080 private void initAbpLoading() | 1080 private void initAbpLoading() |
| 1081 { | 1081 { |
| 1082 getSettings().setJavaScriptEnabled(true); | 1082 getSettings().setJavaScriptEnabled(true); |
| 1083 buildInjectJs(); | 1083 buildInjectJs(); |
| 1084 initEngineProvider(); | 1084 initProvider(); |
| 1085 } | 1085 } |
| 1086 | 1086 |
| 1087 private void initEngineProvider() | 1087 private void initProvider() |
| 1088 { | 1088 { |
| 1089 // if AdblockWebView works as drop-in replacement for WebView 'adblockEngine
Provider' is not set. | 1089 // if AdblockWebView works as drop-in replacement for WebView 'provider' is
not set. |
| 1090 // Thus AdblockWebView is using SingletonEngineProvider instance | 1090 // Thus AdblockWebView is using SingleInstanceEngineProvider instance |
| 1091 if (adblockEngineProvider == null) | 1091 if (provider == null) |
| 1092 { | 1092 { |
| 1093 setAdblockEngineProvider(new SingletonEngineProvider( | 1093 setProvider(new SingleInstanceEngineProvider( |
| 1094 getContext(), AdblockEngine.BASE_PATH_DIRECTORY, debugMode)); | 1094 getContext(), AdblockEngine.BASE_PATH_DIRECTORY, debugMode)); |
| 1095 } | 1095 } |
| 1096 } | 1096 } |
| 1097 | 1097 |
| 1098 private void startAbpLoading(String newUrl) | 1098 private void startAbpLoading(String newUrl) |
| 1099 { | 1099 { |
| 1100 d("Start loading " + newUrl); | 1100 d("Start loading " + newUrl); |
| 1101 | 1101 |
| 1102 loading = true; | 1102 loading = true; |
| 1103 addDomListener = true; | 1103 addDomListener = true; |
| 1104 elementsHidden = false; | 1104 elementsHidden = false; |
| 1105 loadError = null; | 1105 loadError = null; |
| 1106 url = newUrl; | 1106 url = newUrl; |
| 1107 | 1107 |
| 1108 if (url != null) | 1108 if (url != null) |
| 1109 { | 1109 { |
| 1110 try | 1110 try |
| 1111 { | 1111 { |
| 1112 adblockEngineProvider.waitForReady(); | 1112 d("Waiting for adblock engine"); |
| 1113 domain = adblockEngineProvider.getAdblockEngine().getFilterEngine().getH
ostFromURL(url); | 1113 provider.waitForReady(); |
| 1114 |
| 1115 domain = provider.getEngine().getFilterEngine().getHostFromURL(url); |
| 1114 if (domain == null) | 1116 if (domain == null) |
| 1115 { | 1117 { |
| 1116 throw new RuntimeException("Failed to extract domain from " + url); | 1118 throw new RuntimeException("Failed to extract domain from " + url); |
| 1117 } | 1119 } |
| 1118 | 1120 |
| 1119 d("Extracted domain " + domain + " from " + url); | 1121 d("Extracted domain " + domain + " from " + url); |
| 1120 } | 1122 } |
| 1121 catch (Throwable t) | 1123 catch (Throwable t) |
| 1122 { | 1124 { |
| 1123 e("Failed to extract domain from " + url, t); | 1125 e("Failed to extract domain from " + url, t); |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1365 catch (InterruptedException e) | 1367 catch (InterruptedException e) |
| 1366 { | 1368 { |
| 1367 w("Interrupted, returning empty selectors list"); | 1369 w("Interrupted, returning empty selectors list"); |
| 1368 return EMPTY_ELEMHIDE_ARRAY_STRING; | 1370 return EMPTY_ELEMHIDE_ARRAY_STRING; |
| 1369 } | 1371 } |
| 1370 } | 1372 } |
| 1371 } | 1373 } |
| 1372 | 1374 |
| 1373 private void doDispose() | 1375 private void doDispose() |
| 1374 { | 1376 { |
| 1375 adblockEngineProvider.release(); | 1377 w("Disposing AdblockEngine"); |
| 1378 provider.release(); |
| 1376 } | 1379 } |
| 1377 | 1380 |
| 1378 private class DisposeRunnable implements Runnable | 1381 private class DisposeRunnable implements Runnable |
| 1379 { | 1382 { |
| 1380 private Runnable disposeFinished; | 1383 private Runnable disposeFinished; |
| 1381 | 1384 |
| 1382 private DisposeRunnable(Runnable disposeFinished) | 1385 private DisposeRunnable(Runnable disposeFinished) |
| 1383 { | 1386 { |
| 1384 this.disposeFinished = disposeFinished; | 1387 this.disposeFinished = disposeFinished; |
| 1385 } | 1388 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1399 /** | 1402 /** |
| 1400 * Dispose AdblockWebView and internal adblockEngine if it was created | 1403 * Dispose AdblockWebView and internal adblockEngine if it was created |
| 1401 * If external AdblockEngine was passed using `setAdblockEngine()` it should b
e disposed explicitly | 1404 * If external AdblockEngine was passed using `setAdblockEngine()` it should b
e disposed explicitly |
| 1402 * Warning: runnable can be invoked from background thread | 1405 * Warning: runnable can be invoked from background thread |
| 1403 * @param disposeFinished runnable to run when AdblockWebView is disposed | 1406 * @param disposeFinished runnable to run when AdblockWebView is disposed |
| 1404 */ | 1407 */ |
| 1405 public void dispose(final Runnable disposeFinished) | 1408 public void dispose(final Runnable disposeFinished) |
| 1406 { | 1409 { |
| 1407 d("Dispose invoked"); | 1410 d("Dispose invoked"); |
| 1408 | 1411 |
| 1409 if (adblockEngineProvider == null) | 1412 if (provider == null) |
| 1410 { | 1413 { |
| 1411 d("No internal AdblockEngineProvider created"); | 1414 d("No internal AdblockEngineProvider created"); |
| 1412 return; | 1415 return; |
| 1413 } | 1416 } |
| 1414 | 1417 |
| 1415 stopLoading(); | 1418 stopLoading(); |
| 1416 | 1419 |
| 1417 DisposeRunnable disposeRunnable = new DisposeRunnable(disposeFinished); | 1420 DisposeRunnable disposeRunnable = new DisposeRunnable(disposeFinished); |
| 1418 synchronized (elemHideThreadLockObject) | 1421 synchronized (elemHideThreadLockObject) |
| 1419 { | 1422 { |
| 1420 if (elemHideThread != null) | 1423 if (elemHideThread != null) |
| 1421 { | 1424 { |
| 1422 w("Busy with elemhide selectors, delayed disposing scheduled"); | 1425 w("Busy with elemhide selectors, delayed disposing scheduled"); |
| 1423 elemHideThread.setFinishedRunnable(disposeRunnable); | 1426 elemHideThread.setFinishedRunnable(disposeRunnable); |
| 1424 } | 1427 } |
| 1425 else | 1428 else |
| 1426 { | 1429 { |
| 1427 disposeRunnable.run(); | 1430 disposeRunnable.run(); |
| 1428 } | 1431 } |
| 1429 } | 1432 } |
| 1430 } | 1433 } |
| 1431 } | 1434 } |
| OLD | NEW |