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: renamings, updated README Created Dec. 19, 2016, 3:04 p.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 private volatile boolean enabled = true;
71 private List<String> whitelistedDomains;
72
73 private AdblockEngine(final boolean enableElemhide)
74 {
75 this.elemhideEnabled = enableElemhide;
76 }
77
78 public static AppInfo generateAppInfo(final Context context, boolean developme ntBuild)
79 {
80 String version = "0";
81 try
82 {
83 final PackageInfo info = context.getPackageManager().getPackageInfo(contex t.getPackageName(), 0);
84 version = info.versionName;
85 if (developmentBuild)
86 version += "." + info.versionCode;
87 }
88 catch (final NameNotFoundException e)
89 {
90 Log.e(TAG, "Failed to get the application version number", e);
91 }
92 final String sdkVersion = String.valueOf(VERSION.SDK_INT);
93 final String locale = Locale.getDefault().toString().replace('_', '-');
94
95 return AppInfo.builder()
96 .setVersion(version)
97 .setApplicationVersion(sdkVersion)
98 .setLocale(locale)
99 .setDevelopmentBuild(developmentBuild)
100 .build();
101 }
102
103 public static AdblockEngine create(final AppInfo appInfo,
104 final String basePath, boolean enableElemhi de,
105 UpdateAvailableCallback updateAvailableCall back,
106 UpdateCheckDoneCallback updateCheckDoneCall back,
107 ShowNotificationCallback showNotificationCa llback,
108 FilterChangeCallback filterChangeCallback)
109 {
110 Log.w(TAG, "Create");
111
112 final AdblockEngine engine = new AdblockEngine(enableElemhide);
113
114 engine.jsEngine = new JsEngine(appInfo);
115 engine.jsEngine.setDefaultFileSystem(basePath);
116
117 engine.logSystem = new AndroidLogSystem();
118 engine.jsEngine.setLogSystem(engine.logSystem);
119
120 engine.webRequest = new AndroidWebRequest(enableElemhide);
121 engine.jsEngine.setWebRequest(engine.webRequest);
122
123 engine.filterEngine = new FilterEngine(engine.jsEngine);
124
125 engine.updateAvailableCallback = updateAvailableCallback;
126 if (engine.updateAvailableCallback != null)
127 {
128 engine.filterEngine.setUpdateAvailableCallback(updateAvailableCallback);
129 }
130
131 engine.updateCheckDoneCallback = updateCheckDoneCallback;
132
133 engine.showNotificationCallback = showNotificationCallback;
134 if (engine.showNotificationCallback != null)
135 {
136 engine.filterEngine.setShowNotificationCallback(showNotificationCallback);
137 }
138
139 engine.filterChangeCallback = filterChangeCallback;
140 if (engine.filterChangeCallback != null)
141 {
142 engine.filterEngine.setFilterChangeCallback(filterChangeCallback);
143 }
144
145 engine.webRequest.updateSubscriptionURLs(engine.filterEngine);
146
147 return engine;
148 }
149
150 public static AdblockEngine create(final AppInfo appInfo,
151 final String basePath, boolean elemhideEnab led)
152 {
153 return create(appInfo, basePath, elemhideEnabled, null, null, null, null);
154 }
155
156 public void dispose()
157 {
158 Log.w(TAG, "Dispose");
159
160 if (this.logSystem != null)
161 {
162 this.logSystem.dispose();
163 this.logSystem = null;
164 }
165
166 if (this.webRequest != null)
167 {
168 this.webRequest.dispose();
169 this.webRequest = null;
170 }
171
172 if (this.updateAvailableCallback != null)
173 {
174 if (this.filterEngine != null)
175 {
176 this.filterEngine.removeUpdateAvailableCallback();
177 }
178
179 this.updateAvailableCallback.dispose();
180 this.updateAvailableCallback = null;
181 }
182
183 if (this.updateCheckDoneCallback != null)
184 {
185 this.updateCheckDoneCallback.dispose();
186 this.updateCheckDoneCallback = null;
187 }
188
189 if (this.filterChangeCallback != null)
190 {
191 if (this.filterEngine != null)
192 {
193 this.filterEngine.removeFilterChangeCallback();
194 }
195
196 this.filterChangeCallback.dispose();
197 this.filterChangeCallback = null;
198 }
199
200 if (this.showNotificationCallback != null)
201 {
202 if (this.filterEngine != null)
203 {
204 this.filterEngine.removeShowNotificationCallback();
205 }
206
207 this.showNotificationCallback.dispose();
208 this.showNotificationCallback = null;
209 }
210
211 // Safe disposing (just in case)
212 if (this.filterEngine != null)
213 {
214 this.filterEngine.dispose();
215 this.filterEngine = null;
216 }
217
218 if (this.jsEngine != null)
219 {
220 this.jsEngine.dispose();
221 this.jsEngine = null;
222 }
223 }
224
225 public boolean isFirstRun()
226 {
227 return this.filterEngine.isFirstRun();
228 }
229
230 public boolean isElemhideEnabled()
231 {
232 return this.elemhideEnabled;
233 }
234
235 private static org.adblockplus.libadblockplus.android.Subscription convertJsSu bscription(final Subscription jsSubscription)
236 {
237 final org.adblockplus.libadblockplus.android.Subscription subscription =
238 new org.adblockplus.libadblockplus.android.Subscription();
239
240 subscription.title = jsSubscription.getProperty("title").toString();
241 subscription.url = jsSubscription.getProperty("url").toString();
242
243 return subscription;
244 }
245
246 private static org.adblockplus.libadblockplus.android.Subscription[] convertJs Subscriptions(
247 final List<Subscription> jsSubscriptions)
248 {
249 final org.adblockplus.libadblockplus.android.Subscription[] subscriptions =
250 new org.adblockplus.libadblockplus.android.Subscription[jsSubscriptions.si ze()];
251
252 for (int i = 0; i < subscriptions.length; i++)
253 {
254 subscriptions[i] = convertJsSubscription(jsSubscriptions.get(i));
255 }
256
257 return subscriptions;
258 }
259
260 public org.adblockplus.libadblockplus.android.Subscription[] getRecommendedSub scriptions()
261 {
262 return convertJsSubscriptions(this.filterEngine.fetchAvailableSubscriptions( ));
263 }
264
265 public org.adblockplus.libadblockplus.android.Subscription[] getListedSubscrip tions()
266 {
267 return convertJsSubscriptions(this.filterEngine.getListedSubscriptions());
268 }
269
270 public void clearSubscriptions()
271 {
272 for (final Subscription s : this.filterEngine.getListedSubscriptions())
273 {
274 s.removeFromList();
275 }
276 }
277
278 public void setSubscription(final String url)
279 {
280 clearSubscriptions();
281
282 final Subscription sub = this.filterEngine.getSubscription(url);
283 if (sub != null)
284 {
285 sub.addToList();
286 }
287 }
288
289 public void setSubscriptions(Collection<String> urls)
290 {
291 clearSubscriptions();
292
293 for (String eachUrl : urls)
294 {
295 final Subscription sub = this.filterEngine.getSubscription(eachUrl);
296 if (sub != null)
297 {
298 sub.addToList();
299 }
300 }
301 }
302
303 public void refreshSubscriptions()
304 {
305 for (final Subscription s : this.filterEngine.getListedSubscriptions())
306 {
307 s.updateFilters();
308 }
309 }
310
311 public boolean isAcceptableAdsEnabled()
312 {
313 final String url = getAcceptableAdsSubscriptionURL();
314 List<Subscription> subscriptions = this.filterEngine.getListedSubscriptions( );
315 for (Subscription eachSubscription : subscriptions)
316 {
317 if (eachSubscription.getProperty("url").toString().equals(url))
318 {
319 return true;
320 }
321 }
322 return false;
323 }
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 public void setWhitelistedDomains(List<String> domains)
465 {
466 this.whitelistedDomains = domains;
467 }
468
469 public List<String> getWhitelistedDomains()
470 {
471 return whitelistedDomains;
472 }
473 }
OLDNEW

Powered by Google App Engine
This is Rietveld