| Index: mobile/android/thirdparty/org/adblockplus/browser/SubscriptionContainer.java | 
| =================================================================== | 
| --- a/mobile/android/thirdparty/org/adblockplus/browser/SubscriptionContainer.java | 
| +++ b/mobile/android/thirdparty/org/adblockplus/browser/SubscriptionContainer.java | 
| @@ -14,36 +14,40 @@ | 
| * 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.lang.ref.WeakReference; | 
| import java.util.ArrayList; | 
| import java.util.HashMap; | 
| +import java.util.Iterator; | 
| import java.util.List; | 
| import java.util.concurrent.ConcurrentHashMap; | 
| import java.util.concurrent.Semaphore; | 
|  | 
| import org.mozilla.gecko.util.NativeJSObject; | 
| +import org.mozilla.gecko.util.ThreadUtils; | 
| 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 ConcurrentHashMap<String, Boolean> enableState = new ConcurrentHashMap<>(); | 
| 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 final List<SubscriptionContainer.Subscription> entries = new ArrayList<>(); | 
| +  private final HashMap<String, SubscriptionContainer.Subscription> urlMap = new HashMap<>(); | 
| +  private final List<WeakReference<SubscriptionListener>> subscriptionListeners = new ArrayList<>(); | 
|  | 
| private SubscriptionContainer() | 
| { | 
| // prevent external instantiation | 
| } | 
|  | 
| public final static SubscriptionContainer create() | 
| { | 
| @@ -82,17 +86,17 @@ final class SubscriptionContainer implem | 
| } | 
|  | 
| this.entriesReady.acquireUninterruptibly(this.entries.size()); | 
| } | 
| } | 
|  | 
| public List<SubscriptionContainer.Subscription> getSubscriptions(boolean enabled) | 
| { | 
| -    final List<SubscriptionContainer.Subscription> ret = new ArrayList<SubscriptionContainer.Subscription>(); | 
| +    final List<SubscriptionContainer.Subscription> ret = new ArrayList<>(); | 
| for (final SubscriptionContainer.Subscription e : this.entries) | 
| { | 
| if (this.isSubscriptionListed(e.url) == enabled) | 
| { | 
| ret.add(e); | 
| } | 
| } | 
| return ret; | 
| @@ -116,16 +120,48 @@ final class SubscriptionContainer implem | 
| else | 
| { | 
| SubscriptionChangeAction.post(e, SubscriptionPreferenceCategory.subscriptionContainer, | 
| SubscriptionChangeAction.Mode.DISABLE_SUBSCRIPTION); | 
| } | 
| } | 
| } | 
|  | 
| +  public void addSubscriptionListener(SubscriptionListener listener) | 
| +  { | 
| +    final Iterator<WeakReference<SubscriptionListener>> iterator = this.subscriptionListeners.iterator(); | 
| +    boolean shouldAddListener = true; | 
| + | 
| +    while (iterator.hasNext()) | 
| +    { | 
| +      final SubscriptionListener subscriptionListener = iterator.next().get(); | 
| +      if (subscriptionListener != null) | 
| +      { | 
| +        if (subscriptionListener.equals(listener)) | 
| +        { | 
| +          shouldAddListener = false; | 
| +        } | 
| +      } | 
| +      else | 
| +      { | 
| +        iterator.remove(); | 
| +      } | 
| +    } | 
| + | 
| +    if (shouldAddListener) | 
| +    { | 
| +      this.subscriptionListeners.add(new WeakReference<>(listener)); | 
| +    } | 
| +  } | 
| + | 
| +  public void removeSubscriptionListener(SubscriptionListener listener) | 
| +  { | 
| +    this.subscriptionListeners.remove(listener); | 
| +  } | 
| + | 
| @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", ""))); | 
| @@ -229,16 +265,41 @@ final class SubscriptionContainer implem | 
| this.parent.enableState.put(this.subscription.url, | 
| Boolean.valueOf(AddOnBridge.getBooleanFromJsObject(jsObject, "value", false))); | 
| } | 
| finally | 
| { | 
| this.parent.entriesReady.release(); | 
| } | 
| break; | 
| +        case ENABLE_SUBSCRIPTION: | 
| +        case DISABLE_SUBSCRIPTION: | 
| +          this.parent.enableState.put(this.subscription.url, this.mode == Mode.ENABLE_SUBSCRIPTION); | 
| +          final Iterator<WeakReference<SubscriptionListener>> iterator = this.parent.subscriptionListeners.iterator(); | 
| + | 
| +          while (iterator.hasNext()) | 
| +          { | 
| +            final SubscriptionListener listener = iterator.next().get(); | 
| +            if (listener != null) | 
| +            { | 
| +              ThreadUtils.postToUiThread(new Runnable() | 
| +              { | 
| +                @Override | 
| +                public void run() | 
| +                { | 
| +                  listener.onSubscriptionUpdated(); | 
| +                } | 
| +              }); | 
| +            } | 
| +            else | 
| +            { | 
| +              iterator.remove(); | 
| +            } | 
| +          } | 
| +          break; | 
| default: | 
| break; | 
| } | 
| } | 
|  | 
| @Override | 
| public void onApiRequestFailed(String errorMessage) | 
| { | 
| @@ -272,9 +333,14 @@ final class SubscriptionContainer implem | 
| } | 
|  | 
| @Override | 
| public String toString() | 
| { | 
| return this.specialization + " (" + this.title + ") @ " + this.url; | 
| } | 
| } | 
| + | 
| +  public interface SubscriptionListener | 
| +  { | 
| +    void onSubscriptionUpdated(); | 
| +  } | 
| } | 
|  |