| Index: mobile/android/thirdparty/org/adblockplus/browser/SubscriptionContainer.java |
| diff --git a/mobile/android/thirdparty/org/adblockplus/browser/SubscriptionContainer.java b/mobile/android/thirdparty/org/adblockplus/browser/SubscriptionContainer.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1a9a740eb9541e2b06064f9258979b02aec2725a |
| --- /dev/null |
| +++ b/mobile/android/thirdparty/org/adblockplus/browser/SubscriptionContainer.java |
| @@ -0,0 +1,280 @@ |
| +/* |
| + * This file is part of Adblock Plus <https://adblockplus.org/>, |
| + * Copyright (C) 2006-2015 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.browser; |
| + |
| +import java.io.IOException; |
| +import java.io.StringReader; |
| +import java.util.ArrayList; |
| +import java.util.HashMap; |
| +import java.util.List; |
| +import java.util.concurrent.ConcurrentHashMap; |
| +import java.util.concurrent.Semaphore; |
| + |
| +import org.mozilla.gecko.util.NativeJSObject; |
| +import org.xmlpull.v1.XmlPullParser; |
| +import org.xmlpull.v1.XmlPullParserException; |
| + |
| +import android.util.Log; |
| +import android.util.Xml; |
| + |
| +final class SubscriptionContainer implements AdblockPlusApiCallback |
| +{ |
| + private static final String TAG = SubscriptionContainer.class.getName(); |
| + private final ConcurrentHashMap<String, Boolean> enableState = new ConcurrentHashMap<String, Boolean>(); |
| + private final Semaphore entriesReady = new Semaphore(0); |
| + private final List<SubscriptionContainer.Subscription> entries = new ArrayList<SubscriptionContainer.Subscription>(); |
| + private final HashMap<String, SubscriptionContainer.Subscription> urlMap = new HashMap<String, SubscriptionContainer.Subscription>(); |
| + |
| + private SubscriptionContainer() |
| + { |
| + // prevent external instantiation |
| + } |
| + |
| + public final static SubscriptionContainer create() |
| + { |
| + return create(true); |
| + } |
| + |
| + public final static SubscriptionContainer create(final boolean refresh) |
| + { |
| + final SubscriptionContainer sc = new SubscriptionContainer(); |
| + AddOnBridge.queryValue(sc, "subscriptionsXml"); |
| + sc.entriesReady.acquireUninterruptibly(); |
| + |
| + for (final SubscriptionContainer.Subscription e : sc.entries) |
| + { |
| + sc.urlMap.put(e.url, e); |
| + sc.enableState.put(e.url, Boolean.FALSE); |
| + } |
| + |
| + if (refresh) |
| + { |
| + sc.refresh(); |
| + } |
| + |
| + return sc; |
| + } |
| + |
| + public void refresh() |
| + { |
| + if (!this.entries.isEmpty()) |
| + { |
| + for (int i = 0; i < this.entries.size(); i++) |
| + { |
| + SubscriptionChangeAction.post(this.entries.get(i), |
| + this, |
| + SubscriptionChangeAction.Mode.QUERY_SUBSCRIPTION_ENABLED); |
| + } |
| + |
| + this.entriesReady.acquireUninterruptibly(this.entries.size()); |
| + } |
| + } |
| + |
| + public List<SubscriptionContainer.Subscription> getSubscriptions(boolean enabled) |
| + { |
| + final List<SubscriptionContainer.Subscription> ret = new ArrayList<SubscriptionContainer.Subscription>(); |
| + for (final SubscriptionContainer.Subscription e : this.entries) |
| + { |
| + if (this.isSubscriptionListed(e.url) == enabled) |
| + { |
| + ret.add(e); |
| + } |
| + } |
| + return ret; |
| + } |
| + |
| + public boolean isSubscriptionListed(final String url) |
| + { |
| + return this.enableState.containsKey(url) && this.enableState.get(url).booleanValue(); |
| + } |
| + |
| + public void changeSubscriptionState(final String url, final boolean enable) |
| + { |
| + final SubscriptionContainer.Subscription e = this.urlMap.get(url); |
| + if (e != null) |
| + { |
| + if (enable) |
| + { |
| + SubscriptionChangeAction.post(e, SubscriptionPreferenceCategory.subscriptionContainer, |
| + SubscriptionChangeAction.Mode.ENABLE_SUBSCRIPTION); |
| + } |
| + else |
| + { |
| + SubscriptionChangeAction.post(e, SubscriptionPreferenceCategory.subscriptionContainer, |
| + SubscriptionChangeAction.Mode.DISABLE_SUBSCRIPTION); |
| + } |
| + } |
| + } |
| + |
| + @Override |
| + public void onApiRequestSucceeded(NativeJSObject jsObject) |
| + { |
| + final XmlPullParser parser = Xml.newPullParser(); |
| + try |
| + { |
| + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); |
| + parser.setInput(new StringReader(AddOnBridge.getStringFromJsObject(jsObject, "value", ""))); |
| + parser.nextTag(); |
| + parser.require(XmlPullParser.START_TAG, null, "subscriptions"); |
| + while (parser.next() != XmlPullParser.END_TAG) |
| + { |
| + if (parser.getEventType() != XmlPullParser.START_TAG) |
| + { |
| + continue; |
| + } |
| + if ("subscription".equals(parser.getName())) |
| + { |
| + final String title = parser.getAttributeValue(null, "title"); |
| + final String specialization = parser.getAttributeValue(null, "specialization"); |
| + final String url = parser.getAttributeValue(null, "url"); |
| + this.entries.add(new Subscription(title, specialization, url)); |
| + } |
| + parser.next(); |
| + } |
| + } |
| + catch (XmlPullParserException e) |
| + { |
| + Log.e(TAG, "Failed to parse subscriptions.xml: " + e.getMessage(), e); |
| + } |
| + catch (IOException e) |
| + { |
| + Log.e(TAG, "Failed to parse subscriptions.xml: " + e.getMessage(), e); |
| + } |
| + finally |
| + { |
| + this.entriesReady.release(); |
| + } |
| + } |
| + |
| + @Override |
| + public void onApiRequestFailed(String errorMessage) |
| + { |
| + Log.e(TAG, "Error: " + errorMessage); |
| + this.entriesReady.release(); |
| + } |
| + |
| + private static class SubscriptionChangeAction implements AdblockPlusApiCallback |
| + { |
| + private static final String TAG = SubscriptionContainer.SubscriptionChangeAction.class.getName(); |
| + |
| + private final SubscriptionContainer.Subscription subscription; |
| + private final SubscriptionContainer parent; |
| + private final SubscriptionChangeAction.Mode mode; |
| + |
| + public enum Mode |
| + { |
| + QUERY_SUBSCRIPTION_ENABLED, |
| + ENABLE_SUBSCRIPTION, |
| + DISABLE_SUBSCRIPTION, |
| + } |
| + |
| + public SubscriptionChangeAction(final SubscriptionContainer.Subscription subscription, |
| + final SubscriptionContainer parent, |
| + final SubscriptionChangeAction.Mode mode) |
| + { |
| + this.subscription = subscription; |
| + this.parent = parent; |
| + this.mode = mode; |
| + } |
| + |
| + public static SubscriptionContainer.SubscriptionChangeAction post(final SubscriptionContainer.Subscription subscription, |
| + final SubscriptionContainer parent, |
| + final SubscriptionChangeAction.Mode mode) |
| + { |
| + return new SubscriptionChangeAction(subscription, parent, mode).post(); |
| + } |
| + |
| + public SubscriptionContainer.SubscriptionChangeAction post() |
| + { |
| + switch (this.mode) |
| + { |
| + case QUERY_SUBSCRIPTION_ENABLED: |
| + AddOnBridge.querySubscriptionListStatus(this, this.subscription.url); |
| + break; |
| + case ENABLE_SUBSCRIPTION: |
| + AddOnBridge.addSubscription(this, this.subscription.url, this.subscription.title); |
| + break; |
| + case DISABLE_SUBSCRIPTION: |
| + AddOnBridge.removeSubscription(this, this.subscription.url); |
| + break; |
| + default: |
| + break; |
| + } |
| + return this; |
| + } |
| + |
| + @Override |
| + public void onApiRequestSucceeded(NativeJSObject jsObject) |
| + { |
| + switch (this.mode) |
| + { |
| + case QUERY_SUBSCRIPTION_ENABLED: |
| + try |
| + { |
| + this.parent.enableState.put(this.subscription.url, |
| + Boolean.valueOf(AddOnBridge.getBooleanFromJsObject(jsObject, "value", false))); |
| + } |
| + finally |
| + { |
| + this.parent.entriesReady.release(); |
| + } |
| + break; |
| + default: |
| + break; |
| + } |
| + } |
| + |
| + @Override |
| + public void onApiRequestFailed(String errorMessage) |
| + { |
| + switch (this.mode) |
| + { |
| + case QUERY_SUBSCRIPTION_ENABLED: |
| + this.parent.enableState.put(this.subscription.url, Boolean.FALSE); |
| + this.parent.entriesReady.release(); |
| + break; |
| + default: |
| + break; |
| + } |
| + |
| + Log.e(TAG, "Error for '" + this.subscription.url |
| + + "', mode: " + this.mode + ": " |
| + + errorMessage); |
| + } |
| + } |
| + |
| + public static class Subscription |
| + { |
| + public final String title; |
| + public final String specialization; |
| + public final String url; |
| + |
| + public Subscription(final String title, final String specialization, final String url) |
| + { |
| + this.title = title; |
| + this.specialization = specialization; |
| + this.url = url; |
| + } |
| + |
| + @Override |
| + public String toString() |
| + { |
| + return this.specialization + " (" + this.title + ") @ " + this.url; |
| + } |
| + } |
| +} |