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

Powered by Google App Engine
This is Rietveld