Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: libadblockplus-android/src/org/adblockplus/libadblockplus/android/AdblockEngine.java

Issue 29361445: Issue 4399 - Add WebView inheritor with ad blocking (Closed)
Patch Set: applied codestyle: members first, methods then Created Dec. 15, 2016, 11:22 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 Eyeo GmbH
4 *
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
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package org.adblockplus.libadblockplus.android;
19
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Locale;
26 import java.util.Set;
27
28 import org.adblockplus.libadblockplus.AppInfo;
29 import org.adblockplus.libadblockplus.Filter;
30 import org.adblockplus.libadblockplus.FilterChangeCallback;
31 import org.adblockplus.libadblockplus.FilterEngine;
32 import org.adblockplus.libadblockplus.FilterEngine.ContentType;
33 import org.adblockplus.libadblockplus.JsEngine;
34 import org.adblockplus.libadblockplus.LogSystem;
35 import org.adblockplus.libadblockplus.ShowNotificationCallback;
36 import org.adblockplus.libadblockplus.Subscription;
37 import org.adblockplus.libadblockplus.UpdateAvailableCallback;
38 import org.adblockplus.libadblockplus.UpdateCheckDoneCallback;
39
40 import android.content.Context;
41 import android.content.pm.PackageInfo;
42 import android.content.pm.PackageManager.NameNotFoundException;
43 import android.os.Build.VERSION;
44 import android.util.Log;
45
46 public final class AdblockEngine
47 {
48 private static final String TAG = Utils.getTag(AdblockEngine.class);
49
50 /*
51 * The fields below are volatile because:
52 *
53 * I encountered JNI related bugs/crashes caused by JNI backed Java objects. I t seemed that under
54 * certain conditions the objects were optimized away which resulted in crashe s when trying to
55 * release the object, sometimes even on access.
56 *
57 * The only solution that really worked was to declare the variables holding t he references
58 * volatile, this seems to prevent the JNI from 'optimizing away' those object s (as a volatile
59 * variable might be changed at any time from any thread).
60 */
61 private volatile JsEngine jsEngine;
62 private volatile FilterEngine filterEngine;
63 private volatile LogSystem logSystem;
64 private volatile AndroidWebRequest webRequest;
65 private volatile UpdateAvailableCallback updateAvailableCallback;
66 private volatile UpdateCheckDoneCallback updateCheckDoneCallback;
67 private volatile FilterChangeCallback filterChangeCallback;
68 private volatile ShowNotificationCallback showNotificationCallback;
69 private final boolean elemhideEnabled;
70
71 private AdblockEngine(final boolean enableElemhide)
72 {
73 this.elemhideEnabled = enableElemhide;
74 }
75
76 public static AppInfo generateAppInfo(final Context context, boolean developme ntBuild)
77 {
78 String version = "0";
79 try
80 {
81 final PackageInfo info = context.getPackageManager().getPackageInfo(contex t.getPackageName(), 0);
82 version = info.versionName;
83 if (developmentBuild)
84 version += "." + info.versionCode;
85 }
86 catch (final NameNotFoundException e)
87 {
88 Log.e(TAG, "Failed to get the application version number", e);
89 }
90 final String sdkVersion = String.valueOf(VERSION.SDK_INT);
91 final String locale = Locale.getDefault().toString().replace('_', '-');
92
93 return AppInfo.builder()
94 .setVersion(version)
95 .setApplicationVersion(sdkVersion)
96 .setLocale(locale)
97 .setDevelopmentBuild(developmentBuild)
98 .build();
99 }
100
101 public static AdblockEngine create(final AppInfo appInfo,
102 final String basePath, boolean enableElemhi de,
103 UpdateAvailableCallback updateAvailableCall back,
104 UpdateCheckDoneCallback updateCheckDoneCall back,
105 ShowNotificationCallback showNotificationCa llback,
106 FilterChangeCallback filterChangeCallback)
107 {
108 Log.w(TAG, "Create");
109
110 final AdblockEngine engine = new AdblockEngine(enableElemhide);
111
112 engine.jsEngine = new JsEngine(appInfo);
113 engine.jsEngine.setDefaultFileSystem(basePath);
114
115 engine.logSystem = new AndroidLogSystem();
116 engine.jsEngine.setLogSystem(engine.logSystem);
117
118 engine.webRequest = new AndroidWebRequest(enableElemhide);
119 engine.jsEngine.setWebRequest(engine.webRequest);
120
121 engine.filterEngine = new FilterEngine(engine.jsEngine);
122
123 engine.updateAvailableCallback = updateAvailableCallback;
124 if (engine.updateAvailableCallback != null)
125 {
126 engine.filterEngine.setUpdateAvailableCallback(updateAvailableCallback);
127 }
128
129 engine.updateCheckDoneCallback = updateCheckDoneCallback;
130
131 engine.showNotificationCallback = showNotificationCallback;
132 if (engine.showNotificationCallback != null)
133 {
134 engine.filterEngine.setShowNotificationCallback(showNotificationCallback);
135 }
136
137 engine.filterChangeCallback = filterChangeCallback;
138 if (engine.filterChangeCallback != null)
139 {
140 engine.filterEngine.setFilterChangeCallback(filterChangeCallback);
141 }
142
143 engine.webRequest.updateSubscriptionURLs(engine.filterEngine);
144
145 return engine;
146 }
147
148 public static AdblockEngine create(final AppInfo appInfo,
149 final String basePath, boolean elemhideEnab led)
150 {
151 return create(appInfo, basePath, elemhideEnabled, null, null, null, null);
152 }
153
154 public void dispose()
155 {
156 Log.w(TAG, "Dispose");
157
158 if (this.logSystem != null)
159 {
160 this.logSystem.dispose();
161 this.logSystem = null;
162 }
163
164 if (this.webRequest != null)
165 {
166 this.webRequest.dispose();
167 this.webRequest = null;
168 }
169
170 if (this.updateAvailableCallback != null)
171 {
172 if (this.filterEngine != null)
173 {
174 this.filterEngine.removeUpdateAvailableCallback();
175 }
176
177 this.updateAvailableCallback.dispose();
178 this.updateAvailableCallback = null;
179 }
180
181 if (this.updateCheckDoneCallback != null)
182 {
183 this.updateCheckDoneCallback.dispose();
184 this.updateCheckDoneCallback = null;
185 }
186
187 if (this.filterChangeCallback != null)
188 {
189 if (this.filterEngine != null)
190 {
191 this.filterEngine.removeFilterChangeCallback();
192 }
193
194 this.filterChangeCallback.dispose();
195 this.filterChangeCallback = null;
196 }
197
198 if (this.showNotificationCallback != null)
199 {
200 if (this.filterEngine != null)
201 {
202 this.filterEngine.removeShowNotificationCallback();
203 }
204
205 this.showNotificationCallback.dispose();
206 this.showNotificationCallback = null;
207 }
208
209 // Safe disposing (just in case)
210 if (this.filterEngine != null)
211 {
212 this.filterEngine.dispose();
213 this.filterEngine = null;
214 }
215
216 if (this.jsEngine != null)
217 {
218 this.jsEngine.dispose();
219 this.jsEngine = null;
220 }
221 }
222
223 public boolean isFirstRun()
224 {
225 return this.filterEngine.isFirstRun();
226 }
227
228 public boolean isElemhideEnabled()
229 {
230 return this.elemhideEnabled;
231 }
232
233 private static org.adblockplus.libadblockplus.android.Subscription convertJsSu bscription(final Subscription jsSubscription)
234 {
235 final org.adblockplus.libadblockplus.android.Subscription subscription =
236 new org.adblockplus.libadblockplus.android.Subscription();
237
238 subscription.title = jsSubscription.getProperty("title").toString();
239 subscription.url = jsSubscription.getProperty("url").toString();
240
241 return subscription;
242 }
243
244 private static org.adblockplus.libadblockplus.android.Subscription[] convertJs Subscriptions(
245 final List<Subscription> jsSubscriptions)
246 {
247 final org.adblockplus.libadblockplus.android.Subscription[] subscriptions =
248 new org.adblockplus.libadblockplus.android.Subscription[jsSubscriptions.si ze()];
249
250 for (int i = 0; i < subscriptions.length; i++)
251 {
252 subscriptions[i] = convertJsSubscription(jsSubscriptions.get(i));
253 }
254
255 return subscriptions;
256 }
257
258 public org.adblockplus.libadblockplus.android.Subscription[] getRecommendedSub scriptions()
259 {
260 return convertJsSubscriptions(this.filterEngine.fetchAvailableSubscriptions( ));
261 }
262
263 public org.adblockplus.libadblockplus.android.Subscription[] getListedSubscrip tions()
264 {
265 return convertJsSubscriptions(this.filterEngine.getListedSubscriptions());
266 }
267
268 public void clearSubscriptions()
269 {
270 for (final Subscription s : this.filterEngine.getListedSubscriptions())
271 {
272 s.removeFromList();
273 }
274 }
275
276 public void setSubscription(final String url)
277 {
278 clearSubscriptions();
279
280 final Subscription sub = this.filterEngine.getSubscription(url);
281 if (sub != null)
282 {
283 sub.addToList();
284 }
285 }
286
287 public void setSubscriptions(Collection<String> urls)
288 {
289 clearSubscriptions();
290
291 for (String eachUrl : urls)
292 {
293 final Subscription sub = this.filterEngine.getSubscription(eachUrl);
294 if (sub != null)
295 {
296 sub.addToList();
297 }
298 }
299 }
300
301 public void refreshSubscriptions()
302 {
303 for (final Subscription s : this.filterEngine.getListedSubscriptions())
304 {
305 s.updateFilters();
306 }
307 }
308
309 public boolean isAcceptableAdsEnabled()
310 {
311 final String url = getAcceptableAdsSubscriptionURL();
312 List<Subscription> subscriptions = this.filterEngine.getListedSubscriptions( );
313 for (Subscription eachSubscription : subscriptions)
314 {
315 if (eachSubscription.getProperty("url").toString().equals(url))
316 {
317 return true;
318 }
319 }
320 return false;
321 }
322
323 private volatile boolean enabled = true;
diegocarloslima 2016/12/15 14:42:07 This field is still mixed with methods code
anton 2016/12/16 08:32:48 Acknowledged.
324
325 public void setEnabled(final boolean enabled)
326 {
327 this.enabled = enabled;
328 }
329
330 public boolean isEnabled()
331 {
332 return enabled;
333 }
334
335 public String getAcceptableAdsSubscriptionURL()
336 {
337 return this.filterEngine.getPref("subscriptions_exceptionsurl").toString();
338 }
339
340 public void setAcceptableAdsEnabled(final boolean enabled)
341 {
342 final String url = getAcceptableAdsSubscriptionURL();
343 final Subscription sub = this.filterEngine.getSubscription(url);
344 if (sub != null)
345 {
346 if (enabled)
347 {
348 sub.addToList();
349 }
350 else
351 {
352 sub.removeFromList();
353 }
354 }
355 }
356
357 public String getDocumentationLink()
358 {
359 return this.filterEngine.getPref("documentation_link").toString();
360 }
361
362 public boolean matches(final String fullUrl, final ContentType contentType, fi nal String[] referrerChainArray)
363 {
364 if (!enabled)
365 {
366 return false;
367 }
368
369 final Filter filter = this.filterEngine.matches(fullUrl, contentType, referr erChainArray);
370
371 if (filter == null)
372 {
373 return false;
374 }
375
376 // hack: if there is no referrer, block only if filter is domain-specific
377 // (to re-enable in-app ads blocking, proposed on 12.11.2012 Monday meeting)
378 // (documentUrls contains the referrers on Android)
379 try
380 {
381 if (referrerChainArray.length == 0 && (filter.getProperty("text").toString ()).contains("||"))
382 {
383 return false;
384 }
385 } catch (NullPointerException e) {
386 }
387
388 return filter.getType() != Filter.Type.EXCEPTION;
389 }
390
391 public boolean isDocumentWhitelisted(final String url, final String[] referrer ChainArray)
392 {
393 return this.filterEngine.isDocumentWhitelisted(url, referrerChainArray);
394 }
395
396 public boolean isDomainWhitelisted(final String url, final String[] referrerCh ainArray)
397 {
398 if (whitelistedDomains == null)
399 {
400 return false;
401 }
402
403 // using Set to remove duplicates
404 Set<String> referrersAndResourceUrls = new HashSet<String>();
405 if (referrerChainArray != null)
406 {
407 referrersAndResourceUrls.addAll(Arrays.asList(referrerChainArray));
408 }
409 referrersAndResourceUrls.add(url);
410
411 for (String eachUrl : referrersAndResourceUrls)
412 {
413 if (whitelistedDomains.contains(filterEngine.getHostFromURL(eachUrl)))
414 {
415 return true;
416 }
417 }
418
419 return false;
420 }
421
422 public boolean isElemhideWhitelisted(final String url, final String[] referrer ChainArray)
423 {
424 return this.filterEngine.isElemhideWhitelisted(url, referrerChainArray);
425 }
426
427 public List<String> getElementHidingSelectors(final String url, final String d omain, final String[] referrerChainArray)
428 {
429 /*
430 * Issue 3364 (https://issues.adblockplus.org/ticket/3364) introduced the
431 * feature to re-enabled element hiding.
432 *
433 * Nothing changes for Adblock Plus for Android, as `this.elemhideEnabled`
434 * is `false`, which results in an empty list being returned and converted
435 * into a `(String[])null` in AdblockPlus.java, which is the only place
436 * this function here is called from Adblock Plus for Android.
437 *
438 * If element hiding is enabled, then this function now first checks for
439 * possible whitelisting of either the document or element hiding for
440 * the given URL and returns an empty list if so. This is needed to
441 * ensure correct functioning of e.g. acceptable ads.
442 */
443 if (!this.enabled
444 || !this.elemhideEnabled
445 || this.isDomainWhitelisted(url, referrerChainArray)
446 || this.isDocumentWhitelisted(url, referrerChainArray)
447 || this.isElemhideWhitelisted(url, referrerChainArray))
448 {
449 return new ArrayList<String>();
450 }
451 return this.filterEngine.getElementHidingSelectors(domain);
452 }
453
454 public void checkForUpdates()
455 {
456 this.filterEngine.forceUpdateCheck(this.updateCheckDoneCallback);
457 }
458
459 public FilterEngine getFilterEngine()
460 {
461 return this.filterEngine;
462 }
463
464 private List<String> whitelistedDomains;
diegocarloslima 2016/12/15 14:42:07 This field is still mixed with methods code
anton 2016/12/16 08:32:47 Acknowledged.
465
466 public void setWhitelistedDomains(List<String> domains)
467 {
468 this.whitelistedDomains = domains;
469 }
470
471 public List<String> getWhitelistedDomains()
472 {
473 return whitelistedDomains;
474 }
475 }
OLDNEW

Powered by Google App Engine
This is Rietveld