Index: libadblockplus-android/src/org/adblockplus/libadblockplus/android/AdblockEngine.java
diff --git a/libadblockplus-android/src/org/adblockplus/libadblockplus/android/AdblockEngine.java b/libadblockplus-android/src/org/adblockplus/libadblockplus/android/AdblockEngine.java
deleted file mode 100644
index f5143695e6fb20d91b9d7878497873f4ca40e456..0000000000000000000000000000000000000000
--- a/libadblockplus-android/src/org/adblockplus/libadblockplus/android/AdblockEngine.java
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-present eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.adblockplus.libadblockplus.android;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import org.adblockplus.libadblockplus.AppInfo;
-import org.adblockplus.libadblockplus.Filter;
-import org.adblockplus.libadblockplus.FilterChangeCallback;
-import org.adblockplus.libadblockplus.FilterEngine;
-import org.adblockplus.libadblockplus.FilterEngine.ContentType;
-import org.adblockplus.libadblockplus.IsAllowedConnectionCallback;
-import org.adblockplus.libadblockplus.JsValue;
-import org.adblockplus.libadblockplus.LogSystem;
-import org.adblockplus.libadblockplus.Platform;
-import org.adblockplus.libadblockplus.ShowNotificationCallback;
-import org.adblockplus.libadblockplus.Subscription;
-import org.adblockplus.libadblockplus.UpdateAvailableCallback;
-import org.adblockplus.libadblockplus.UpdateCheckDoneCallback;
-import org.adblockplus.libadblockplus.WebRequest;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.os.Build.VERSION;
-import android.util.Log;
-
-public final class AdblockEngine
-{
-  // default base path to store subscription files in android app
-  public static final String BASE_PATH_DIRECTORY = "adblock";
-
-  private static final String TAG = Utils.getTag(AdblockEngine.class);
-
-  /*
-   * The fields below are volatile because:
-   *
-   * I encountered JNI related bugs/crashes caused by JNI backed Java objects. It seemed that under
-   * certain conditions the objects were optimized away which resulted in crashes when trying to
-   * release the object, sometimes even on access.
-   *
-   * The only solution that really worked was to declare the variables holding the references
-   * volatile, this seems to prevent the JNI from 'optimizing away' those objects (as a volatile
-   * variable might be changed at any time from any thread).
-   */
-  private volatile Platform platform;
-  private volatile FilterEngine filterEngine;
-  private volatile LogSystem logSystem;
-  private volatile WebRequest webRequest;
-  private volatile UpdateAvailableCallback updateAvailableCallback;
-  private volatile UpdateCheckDoneCallback updateCheckDoneCallback;
-  private volatile FilterChangeCallback filterChangeCallback;
-  private volatile ShowNotificationCallback showNotificationCallback;
-  private volatile boolean elemhideEnabled;
-  private volatile boolean enabled = true;
-  private volatile List<String> whitelistedDomains;
-
-  public static AppInfo generateAppInfo(final Context context, boolean developmentBuild,
-                                        String application, String applicationVersion)
-  {
-    final String sdkVersion = String.valueOf(VERSION.SDK_INT);
-    final String locale = Locale.getDefault().toString().replace('_', '-');
-
-    AppInfo.Builder builder =
-      AppInfo
-        .builder()
-        .setApplicationVersion(sdkVersion)
-        .setLocale(locale)
-        .setDevelopmentBuild(developmentBuild);
-
-    if (application != null)
-    {
-      builder.setApplication(application);
-    }
-
-    if (applicationVersion != null)
-    {
-      builder.setApplicationVersion(applicationVersion);
-    }
-
-    return builder.build();
-  }
-
-  public static AppInfo generateAppInfo(final Context context, boolean developmentBuild)
-  {
-    try
-    {
-      PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
-      String application = context.getPackageName();
-      String applicationVersion = packageInfo.versionName;
-
-      return generateAppInfo(context, developmentBuild, application, applicationVersion);
-    }
-    catch (PackageManager.NameNotFoundException e)
-    {
-      throw new RuntimeException(e);
-    }
-  }
-
-  /**
-   * Builds Adblock engine
-   */
-  public static class Builder
-  {
-    private Context context;
-    private Map<String, Integer> urlToResourceIdMap;
-    private AndroidWebRequestResourceWrapper.Storage resourceStorage;
-    private AndroidWebRequest androidWebRequest;
-    private AppInfo appInfo;
-    private String basePath;
-    private IsAllowedConnectionCallback isAllowedConnectionCallback;
-    private Long v8IsolateProviderPtr;
-
-    private AdblockEngine engine;
-
-    protected Builder(final AppInfo appInfo, final String basePath)
-    {
-      engine = new AdblockEngine();
-      engine.elemhideEnabled = true;
-
-      // we can't create JsEngine and FilterEngine right now as it starts to download subscriptions
-      // and requests (AndroidWebRequest and probbaly wrappers) are not specified yet
-      this.appInfo = appInfo;
-      this.basePath = basePath;
-    }
-
-    public Builder enableElementHiding(boolean enable)
-    {
-      engine.elemhideEnabled = enable;
-      return this;
-    }
-
-    public Builder preloadSubscriptions(Context context,
-                                        Map<String, Integer> urlToResourceIdMap,
-                                        AndroidWebRequestResourceWrapper.Storage storage)
-    {
-      this.context = context;
-      this.urlToResourceIdMap = urlToResourceIdMap;
-      this.resourceStorage = storage;
-      return this;
-    }
-
-    public Builder setIsAllowedConnectionCallback(IsAllowedConnectionCallback callback)
-    {
-      this.isAllowedConnectionCallback = callback;
-      return this;
-    }
-
-    public Builder useV8IsolateProvider(long v8IsolateProviderPtr)
-    {
-      this.v8IsolateProviderPtr = v8IsolateProviderPtr;
-      return this;
-    }
-
-    public Builder setUpdateAvailableCallback(UpdateAvailableCallback callback)
-    {
-      engine.updateAvailableCallback = callback;
-      return this;
-    }
-
-    public Builder setUpdateCheckDoneCallback(UpdateCheckDoneCallback callback)
-    {
-      engine.updateCheckDoneCallback = callback;
-      return this;
-    }
-
-    public Builder setShowNotificationCallback(ShowNotificationCallback callback)
-    {
-      engine.showNotificationCallback = callback;
-      return this;
-    }
-
-    public Builder setFilterChangeCallback(FilterChangeCallback callback)
-    {
-      engine.filterChangeCallback = callback;
-      return this;
-    }
-
-    private void initRequests()
-    {
-      androidWebRequest = new AndroidWebRequest(engine.elemhideEnabled, true);
-      engine.webRequest = androidWebRequest;
-
-      if (urlToResourceIdMap != null)
-      {
-        AndroidWebRequestResourceWrapper wrapper = new AndroidWebRequestResourceWrapper(
-          context, engine.webRequest, urlToResourceIdMap, resourceStorage);
-        wrapper.setListener(new AndroidWebRequestResourceWrapper.Listener()
-        {
-          @Override
-          public void onIntercepted(String url, int resourceId)
-          {
-            Log.d(TAG, "Force subscription update for intercepted URL " + url);
-            if (engine.filterEngine != null)
-            {
-              engine.filterEngine.updateFiltersAsync(url);
-            }
-          }
-        });
-
-        engine.webRequest = wrapper;
-      }
-    }
-
-    private void initCallbacks()
-    {
-      if (engine.updateAvailableCallback != null)
-      {
-        engine.filterEngine.setUpdateAvailableCallback(engine.updateAvailableCallback);
-      }
-
-      if (engine.showNotificationCallback != null)
-      {
-        engine.filterEngine.setShowNotificationCallback(engine.showNotificationCallback);
-      }
-
-      if (engine.filterChangeCallback != null)
-      {
-        engine.filterEngine.setFilterChangeCallback(engine.filterChangeCallback);
-      }
-    }
-
-    public AdblockEngine build()
-    {
-      initRequests();
-
-      // webRequest should be ready to be used passed right after JsEngine is created
-      createEngines();
-
-      initCallbacks();
-
-      if (!engine.elemhideEnabled)
-      {
-        androidWebRequest.updateSubscriptionURLs(engine.filterEngine);
-      }
-
-      return engine;
-    }
-
-    private void createEngines()
-    {
-      engine.logSystem = new AndroidLogSystem();
-      engine.platform = new Platform(engine.logSystem, engine.webRequest, basePath);
-      if (v8IsolateProviderPtr != null)
-      {
-        engine.platform.setUpJsEngine(appInfo, v8IsolateProviderPtr);
-      }
-      else
-      {
-        engine.platform.setUpJsEngine(appInfo);
-      }
-      engine.platform.setUpFilterEngine(isAllowedConnectionCallback);
-      engine.filterEngine = engine.platform.getFilterEngine();
-    }
-  }
-
-  public static Builder builder(AppInfo appInfo, String basePath)
-  {
-    return new Builder(appInfo, basePath);
-  }
-
-  public void dispose()
-  {
-    Log.w(TAG, "Dispose");
-
-    // engines first
-    if (this.filterEngine != null)
-    {
-      if (this.updateAvailableCallback != null)
-      {
-        this.filterEngine.removeUpdateAvailableCallback();
-      }
-
-      if (this.filterChangeCallback != null)
-      {
-        this.filterEngine.removeFilterChangeCallback();
-      }
-
-      if (this.showNotificationCallback != null)
-      {
-        this.filterEngine.removeShowNotificationCallback();
-      }
-
-      this.platform.dispose();
-      this.platform = null;
-    }
-
-    // callbacks then
-    if (this.updateAvailableCallback != null)
-    {
-      this.updateAvailableCallback.dispose();
-      this.updateAvailableCallback = null;
-    }
-
-    if (this.filterChangeCallback != null)
-    {
-      this.filterChangeCallback.dispose();
-      this.filterChangeCallback = null;
-    }
-
-    if (this.showNotificationCallback != null)
-    {
-      this.showNotificationCallback.dispose();
-      this.showNotificationCallback = null;
-    }
-  }
-
-  public boolean isFirstRun()
-  {
-    return this.filterEngine.isFirstRun();
-  }
-
-  public boolean isElemhideEnabled()
-  {
-    return this.elemhideEnabled;
-  }
-
-  private static org.adblockplus.libadblockplus.android.Subscription convertJsSubscription(final Subscription jsSubscription)
-  {
-    final org.adblockplus.libadblockplus.android.Subscription subscription =
-      new org.adblockplus.libadblockplus.android.Subscription();
-
-    JsValue jsTitle = jsSubscription.getProperty("title");
-    try
-    {
-      subscription.title = jsTitle.toString();
-    }
-    finally
-    {
-      jsTitle.dispose();
-    }
-
-    JsValue jsUrl = jsSubscription.getProperty("url");
-    try
-    {
-      subscription.url = jsUrl.toString();
-    }
-    finally
-    {
-      jsUrl.dispose();
-    }
-
-    JsValue jsSpecialization = jsSubscription.getProperty("specialization");
-    try
-    {
-      subscription.specialization = jsSpecialization.toString();
-    }
-    finally
-    {
-      jsSpecialization.dispose();
-    }
-
-    return subscription;
-  }
-
-  private static org.adblockplus.libadblockplus.android.Subscription[] convertJsSubscriptions(
-    final List<Subscription> jsSubscriptions)
-  {
-    final org.adblockplus.libadblockplus.android.Subscription[] subscriptions =
-      new org.adblockplus.libadblockplus.android.Subscription[jsSubscriptions.size()];
-
-    for (int i = 0; i < subscriptions.length; i++)
-    {
-      subscriptions[i] = convertJsSubscription(jsSubscriptions.get(i));
-    }
-
-    return subscriptions;
-  }
-
-  public org.adblockplus.libadblockplus.android.Subscription[] getRecommendedSubscriptions()
-  {
-    List<Subscription> subscriptions = this.filterEngine.fetchAvailableSubscriptions();
-    try
-    {
-      return convertJsSubscriptions(subscriptions);
-    }
-    finally
-    {
-      for (Subscription eachSubscription : subscriptions)
-      {
-        eachSubscription.dispose();
-      }
-    }
-  }
-
-  public org.adblockplus.libadblockplus.android.Subscription[] getListedSubscriptions()
-  {
-    List<Subscription> subscriptions = this.filterEngine.getListedSubscriptions();
-    try
-    {
-      return convertJsSubscriptions(subscriptions);
-    }
-    finally
-    {
-      for (Subscription eachSubscription : subscriptions)
-      {
-        eachSubscription.dispose();
-      }
-    }
-  }
-
-  public void clearSubscriptions()
-  {
-    for (final Subscription s : this.filterEngine.getListedSubscriptions())
-    {
-      try
-      {
-        s.removeFromList();
-      }
-      finally
-      {
-        s.dispose();
-      }
-    }
-  }
-
-  public void setSubscription(final String url)
-  {
-    clearSubscriptions();
-
-    final Subscription sub = this.filterEngine.getSubscription(url);
-    if (sub != null)
-    {
-      try
-      {
-        sub.addToList();
-      }
-      finally
-      {
-        sub.dispose();
-      }
-    }
-  }
-
-  public void setSubscriptions(Collection<String> urls)
-  {
-    clearSubscriptions();
-
-    for (String eachUrl : urls)
-    {
-      final Subscription sub = this.filterEngine.getSubscription(eachUrl);
-      if (sub != null)
-      {
-        try
-        {
-          sub.addToList();
-        }
-        finally
-        {
-          sub.dispose();
-        }
-      }
-    }
-  }
-
-  public void setEnabled(final boolean enabled)
-  {
-    this.enabled = enabled;
-  }
-
-  public boolean isEnabled()
-  {
-    return enabled;
-  }
-
-  public String getAcceptableAdsSubscriptionURL()
-  {
-    return filterEngine.getAcceptableAdsSubscriptionURL();
-  }
-
-  public boolean isAcceptableAdsEnabled()
-  {
-    return filterEngine.isAcceptableAdsEnabled();
-  }
-
-  public void setAcceptableAdsEnabled(final boolean enabled)
-  {
-    filterEngine.setAcceptableAdsEnabled(enabled);
-  }
-
-  public String getDocumentationLink()
-  {
-    JsValue jsPref = this.filterEngine.getPref("documentation_link");
-    try
-    {
-      return jsPref.toString();
-    }
-    finally
-    {
-      jsPref.dispose();
-    }
-  }
-
-  public boolean matches(final String fullUrl, final ContentType contentType, final String[] referrerChainArray)
-  {
-    if (!enabled)
-    {
-      return false;
-    }
-
-    final Filter filter = this.filterEngine.matches(fullUrl, contentType, referrerChainArray);
-
-    if (filter == null)
-    {
-      return false;
-    }
-
-    try
-    {
-      // hack: if there is no referrer, block only if filter is domain-specific
-      // (to re-enable in-app ads blocking, proposed on 12.11.2012 Monday meeting)
-      // (documentUrls contains the referrers on Android)
-      try
-      {
-        JsValue jsText = filter.getProperty("text");
-        try
-        {
-          if (referrerChainArray.length == 0 && (jsText.toString()).contains("||"))
-          {
-            return false;
-          }
-        }
-        finally
-        {
-          jsText.dispose();
-        }
-      }
-      catch (NullPointerException e)
-      {
-      }
-
-      return filter.getType() != Filter.Type.EXCEPTION;
-    }
-    finally
-    {
-      filter.dispose();
-    }
-  }
-
-  public boolean isDocumentWhitelisted(final String url, final String[] referrerChainArray)
-  {
-    return this.filterEngine.isDocumentWhitelisted(url, referrerChainArray);
-  }
-
-  public boolean isDomainWhitelisted(final String url, final String[] referrerChainArray)
-  {
-    if (whitelistedDomains == null)
-    {
-      return false;
-    }
-
-    // using Set to remove duplicates
-    Set<String> referrersAndResourceUrls = new HashSet<String>();
-    if (referrerChainArray != null)
-    {
-      referrersAndResourceUrls.addAll(Arrays.asList(referrerChainArray));
-    }
-    referrersAndResourceUrls.add(url);
-
-    for (String eachUrl : referrersAndResourceUrls)
-    {
-      if (whitelistedDomains.contains(filterEngine.getHostFromURL(eachUrl)))
-      {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  public boolean isElemhideWhitelisted(final String url, final String[] referrerChainArray)
-  {
-    return this.filterEngine.isElemhideWhitelisted(url, referrerChainArray);
-  }
-
-  public List<String> getElementHidingSelectors(final String url, final String domain, final String[] referrerChainArray)
-  {
-    /*
-     * Issue 3364 (https://issues.adblockplus.org/ticket/3364) introduced the
-     * feature to re-enabled element hiding.
-     *
-     * Nothing changes for Adblock Plus for Android, as `this.elemhideEnabled`
-     * is `false`, which results in an empty list being returned and converted
-     * into a `(String[])null` in AdblockPlus.java, which is the only place
-     * this function here is called from Adblock Plus for Android.
-     *
-     * If element hiding is enabled, then this function now first checks for
-     * possible whitelisting of either the document or element hiding for
-     * the given URL and returns an empty list if so. This is needed to
-     * ensure correct functioning of e.g. acceptable ads.
-     */
-    if (!this.enabled
-        || !this.elemhideEnabled
-        || this.isDomainWhitelisted(url, referrerChainArray)
-        || this.isDocumentWhitelisted(url, referrerChainArray)
-        || this.isElemhideWhitelisted(url, referrerChainArray))
-    {
-      return new ArrayList<String>();
-    }
-    return this.filterEngine.getElementHidingSelectors(domain);
-  }
-
-  public void checkForUpdates()
-  {
-    this.filterEngine.forceUpdateCheck(this.updateCheckDoneCallback);
-  }
-
-  public FilterEngine getFilterEngine()
-  {
-    return this.filterEngine;
-  }
-
-  public void setWhitelistedDomains(List<String> domains)
-  {
-    this.whitelistedDomains = domains;
-  }
-
-  public List<String> getWhitelistedDomains()
-  {
-    return whitelistedDomains;
-  }
-}
