| LEFT | RIGHT | 
|---|
| (no file at all) |  | 
|  | 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.List; | 
|  | 22 import java.util.Locale; | 
|  | 23 | 
|  | 24 import org.adblockplus.libadblockplus.AppInfo; | 
|  | 25 import org.adblockplus.libadblockplus.Filter; | 
|  | 26 import org.adblockplus.libadblockplus.FilterChangeCallback; | 
|  | 27 import org.adblockplus.libadblockplus.FilterEngine; | 
|  | 28 import org.adblockplus.libadblockplus.FilterEngine.ContentType; | 
|  | 29 import org.adblockplus.libadblockplus.JsEngine; | 
|  | 30 import org.adblockplus.libadblockplus.LogSystem; | 
|  | 31 import org.adblockplus.libadblockplus.ShowNotificationCallback; | 
|  | 32 import org.adblockplus.libadblockplus.Subscription; | 
|  | 33 import org.adblockplus.libadblockplus.UpdateAvailableCallback; | 
|  | 34 import org.adblockplus.libadblockplus.UpdateCheckDoneCallback; | 
|  | 35 | 
|  | 36 import android.content.Context; | 
|  | 37 import android.content.pm.PackageInfo; | 
|  | 38 import android.content.pm.PackageManager.NameNotFoundException; | 
|  | 39 import android.os.Build.VERSION; | 
|  | 40 import android.util.Log; | 
|  | 41 | 
|  | 42 public final class AdblockEngine | 
|  | 43 { | 
|  | 44   private static final String TAG = Utils.getTag(AdblockEngine.class); | 
|  | 45 | 
|  | 46   private final Context context; | 
|  | 47 | 
|  | 48   /* | 
|  | 49    * The fields below are volatile because: | 
|  | 50    * | 
|  | 51    * I encountered JNI related bugs/crashes caused by JNI backed Java objects. I
     t seemed that under | 
|  | 52    * certain conditions the objects were optimized away which resulted in crashe
     s when trying to | 
|  | 53    * release the object, sometimes even on access. | 
|  | 54    * | 
|  | 55    * The only solution that really worked was to declare the variables holding t
     he references | 
|  | 56    * volatile, this seems to prevent the JNI from 'optimizing away' those object
     s (as a volatile | 
|  | 57    * variable might be changed at any time from any thread). | 
|  | 58    */ | 
|  | 59   private volatile JsEngine jsEngine; | 
|  | 60   private volatile FilterEngine filterEngine; | 
|  | 61   private volatile LogSystem logSystem; | 
|  | 62   private volatile AndroidWebRequest webRequest; | 
|  | 63   private volatile UpdateAvailableCallback updateAvailableCallback; | 
|  | 64   private volatile UpdateCheckDoneCallback updateCheckDoneCallback; | 
|  | 65   private volatile FilterChangeCallback filterChangeCallback; | 
|  | 66   private volatile ShowNotificationCallback showNotificationCallback; | 
|  | 67   private final boolean elemhideEnabled; | 
|  | 68 | 
|  | 69   private AdblockEngine(final Context context, final boolean enableElemhide) | 
|  | 70   { | 
|  | 71     this.context = context; | 
|  | 72     this.elemhideEnabled = enableElemhide; | 
|  | 73   } | 
|  | 74 | 
|  | 75   public static AppInfo generateAppInfo(final Context context, boolean developme
     ntBuild) | 
|  | 76   { | 
|  | 77     String version = "0"; | 
|  | 78     try | 
|  | 79     { | 
|  | 80       final PackageInfo info = context.getPackageManager().getPackageInfo(contex
     t.getPackageName(), 0); | 
|  | 81       version = info.versionName; | 
|  | 82       if (developmentBuild) | 
|  | 83         version += "." + info.versionCode; | 
|  | 84     } | 
|  | 85     catch (final NameNotFoundException e) | 
|  | 86     { | 
|  | 87       Log.e(TAG, "Failed to get the application version number", e); | 
|  | 88     } | 
|  | 89     final String sdkVersion = String.valueOf(VERSION.SDK_INT); | 
|  | 90     final String locale = Locale.getDefault().toString().replace('_', '-'); | 
|  | 91 | 
|  | 92     return AppInfo.builder() | 
|  | 93         .setVersion(version) | 
|  | 94         .setApplicationVersion(sdkVersion) | 
|  | 95         .setLocale(locale) | 
|  | 96         .setDevelopmentBuild(developmentBuild) | 
|  | 97         .build(); | 
|  | 98   } | 
|  | 99 | 
|  | 100   public static AdblockEngine create(final Context context, final AppInfo appInf
     o, final String basePath) | 
|  | 101   { | 
|  | 102     return create(context, appInfo, basePath, false); | 
|  | 103   } | 
|  | 104 | 
|  | 105   public static AdblockEngine create(final Context context, final AppInfo appInf
     o, final String basePath, boolean enableElemhide) | 
|  | 106   { | 
|  | 107     final AdblockEngine engine = new AdblockEngine(context, enableElemhide); | 
|  | 108 | 
|  | 109     engine.jsEngine = new JsEngine(appInfo); | 
|  | 110     engine.jsEngine.setDefaultFileSystem(basePath); | 
|  | 111 | 
|  | 112     engine.logSystem = new AndroidLogSystem(); | 
|  | 113     engine.jsEngine.setLogSystem(engine.logSystem); | 
|  | 114 | 
|  | 115     engine.webRequest = new AndroidWebRequest(enableElemhide); | 
|  | 116     engine.jsEngine.setWebRequest(engine.webRequest); | 
|  | 117 | 
|  | 118     engine.filterEngine = new FilterEngine(engine.jsEngine); | 
|  | 119 | 
|  | 120     engine.webRequest.updateSubscriptionURLs(engine.filterEngine); | 
|  | 121 | 
|  | 122     return engine; | 
|  | 123   } | 
|  | 124 | 
|  | 125   public void dispose() | 
|  | 126   { | 
|  | 127     // Safe disposing (just in case) | 
|  | 128     if (this.filterEngine != null) | 
|  | 129     { | 
|  | 130       this.filterEngine.dispose(); | 
|  | 131       this.filterEngine = null; | 
|  | 132     } | 
|  | 133 | 
|  | 134     if (this.jsEngine != null) | 
|  | 135     { | 
|  | 136       this.jsEngine.dispose(); | 
|  | 137       this.jsEngine = null; | 
|  | 138     } | 
|  | 139 | 
|  | 140     if (this.logSystem != null) | 
|  | 141     { | 
|  | 142       this.logSystem.dispose(); | 
|  | 143       this.logSystem = null; | 
|  | 144     } | 
|  | 145 | 
|  | 146     if (this.webRequest != null) | 
|  | 147     { | 
|  | 148       this.webRequest.dispose(); | 
|  | 149       this.webRequest = null; | 
|  | 150     } | 
|  | 151 | 
|  | 152     if (this.updateAvailableCallback != null) | 
|  | 153     { | 
|  | 154       this.updateAvailableCallback.dispose(); | 
|  | 155       this.updateAvailableCallback = null; | 
|  | 156     } | 
|  | 157 | 
|  | 158     if (this.updateCheckDoneCallback != null) | 
|  | 159     { | 
|  | 160       this.updateCheckDoneCallback.dispose(); | 
|  | 161       this.updateCheckDoneCallback = null; | 
|  | 162     } | 
|  | 163 | 
|  | 164     if (this.filterChangeCallback != null) | 
|  | 165     { | 
|  | 166       this.filterChangeCallback.dispose(); | 
|  | 167       this.filterChangeCallback = null; | 
|  | 168     } | 
|  | 169 | 
|  | 170     if (this.showNotificationCallback != null) | 
|  | 171     { | 
|  | 172       this.showNotificationCallback.dispose(); | 
|  | 173       this.showNotificationCallback = null; | 
|  | 174     } | 
|  | 175   } | 
|  | 176 | 
|  | 177   public boolean isFirstRun() | 
|  | 178   { | 
|  | 179     return this.filterEngine.isFirstRun(); | 
|  | 180   } | 
|  | 181 | 
|  | 182   public boolean isElemhideEnabled() | 
|  | 183   { | 
|  | 184     return this.elemhideEnabled; | 
|  | 185   } | 
|  | 186 | 
|  | 187   public void setSubscription(final String url) | 
|  | 188   { | 
|  | 189     for (final Subscription s : this.filterEngine.getListedSubscriptions()) | 
|  | 190     { | 
|  | 191       s.removeFromList(); | 
|  | 192     } | 
|  | 193 | 
|  | 194     final Subscription sub = this.filterEngine.getSubscription(url); | 
|  | 195     if (sub != null) | 
|  | 196     { | 
|  | 197       sub.addToList(); | 
|  | 198     } | 
|  | 199   } | 
|  | 200 | 
|  | 201   public void refreshSubscriptions() | 
|  | 202   { | 
|  | 203     for (final Subscription s : this.filterEngine.getListedSubscriptions()) | 
|  | 204     { | 
|  | 205       s.updateFilters(); | 
|  | 206     } | 
|  | 207   } | 
|  | 208 | 
|  | 209   public boolean isAcceptableAdsEnabled() | 
|  | 210   { | 
|  | 211     final String url = this.filterEngine.getPref("subscriptions_exceptionsurl").
     toString(); | 
|  | 212     List<Subscription> subscriptions = this.filterEngine.getListedSubscriptions(
     ); | 
|  | 213     for (Subscription eachSubscription : subscriptions) | 
|  | 214     { | 
|  | 215       if (eachSubscription.getProperty("url").toString().equals(url)) | 
|  | 216       { | 
|  | 217         return true; | 
|  | 218       } | 
|  | 219     } | 
|  | 220     return false; | 
|  | 221   } | 
|  | 222 | 
|  | 223   public void setAcceptableAdsEnabled(final boolean enabled) | 
|  | 224   { | 
|  | 225     final String url = this.filterEngine.getPref("subscriptions_exceptionsurl").
     toString(); | 
|  | 226     final Subscription sub = this.filterEngine.getSubscription(url); | 
|  | 227     if (sub != null) | 
|  | 228     { | 
|  | 229       if (enabled) | 
|  | 230       { | 
|  | 231         sub.addToList(); | 
|  | 232       } | 
|  | 233       else | 
|  | 234       { | 
|  | 235         sub.removeFromList(); | 
|  | 236       } | 
|  | 237     } | 
|  | 238   } | 
|  | 239 | 
|  | 240   public String getDocumentationLink() | 
|  | 241   { | 
|  | 242     return this.filterEngine.getPref("documentation_link").toString(); | 
|  | 243   } | 
|  | 244 | 
|  | 245   public boolean matches(final String fullUrl, final ContentType contentType, fi
     nal String[] referrerChainArray) | 
|  | 246   { | 
|  | 247     final Filter filter = this.filterEngine.matches(fullUrl, contentType, referr
     erChainArray); | 
|  | 248 | 
|  | 249     if (filter == null) | 
|  | 250     { | 
|  | 251       return false; | 
|  | 252     } | 
|  | 253 | 
|  | 254     // hack: if there is no referrer, block only if filter is domain-specific | 
|  | 255     // (to re-enable in-app ads blocking, proposed on 12.11.2012 Monday meeting) | 
|  | 256     // (documentUrls contains the referrers on Android) | 
|  | 257     try | 
|  | 258     { | 
|  | 259       if (referrerChainArray.length == 0 && (filter.getProperty("text").toString
     ()).contains("||")) | 
|  | 260       { | 
|  | 261         return false; | 
|  | 262       } | 
|  | 263     } catch (NullPointerException e) { | 
|  | 264     } | 
|  | 265 | 
|  | 266     return filter.getType() != Filter.Type.EXCEPTION; | 
|  | 267   } | 
|  | 268 | 
|  | 269   public boolean isDocumentWhitelisted(final String url, final String[] referrer
     ChainArray) | 
|  | 270   { | 
|  | 271     return this.filterEngine.isDocumentWhitelisted(url, referrerChainArray); | 
|  | 272   } | 
|  | 273 | 
|  | 274   public boolean isElemhideWhitelisted(final String url, final String[] referrer
     ChainArray) | 
|  | 275   { | 
|  | 276     return this.filterEngine.isElemhideWhitelisted(url, referrerChainArray); | 
|  | 277   } | 
|  | 278 | 
|  | 279   public List<String> getElementHidingSelectors(final String url, final String d
     omain, final String[] referrerChainArray) | 
|  | 280   { | 
|  | 281     /* | 
|  | 282      * Issue 3364 (https://issues.adblockplus.org/ticket/3364) introduced the | 
|  | 283      * feature to re-enabled element hiding. | 
|  | 284      * | 
|  | 285      * Nothing changes for Adblock Plus for Android, as `this.elemhideEnabled` | 
|  | 286      * is `false`, which results in an empty list being returned and converted | 
|  | 287      * into a `(String[])null` in AdblockPlus.java, which is the only place | 
|  | 288      * this function here is called from Adblock Plus for Android. | 
|  | 289      * | 
|  | 290      * If element hiding is enabled, then this function now first checks for | 
|  | 291      * possible whitelisting of either the document or element hiding for | 
|  | 292      * the given URL and returns an empty list if so. This is needed to | 
|  | 293      * ensure correct functioning of e.g. acceptable ads. | 
|  | 294      */ | 
|  | 295     if (!this.elemhideEnabled | 
|  | 296         || this.isDocumentWhitelisted(url, referrerChainArray) | 
|  | 297         || this.isElemhideWhitelisted(url, referrerChainArray)) | 
|  | 298     { | 
|  | 299       return new ArrayList<String>(); | 
|  | 300     } | 
|  | 301     return this.filterEngine.getElementHidingSelectors(domain); | 
|  | 302   } | 
|  | 303 | 
|  | 304   public void checkForUpdates() | 
|  | 305   { | 
|  | 306     this.filterEngine.forceUpdateCheck(this.updateCheckDoneCallback); | 
|  | 307   } | 
|  | 308 | 
|  | 309   public FilterEngine getFilterEngine() | 
|  | 310   { | 
|  | 311     return this.filterEngine; | 
|  | 312   } | 
|  | 313 } | 
| LEFT | RIGHT | 
|---|