| Index: adblockplussbrowser/src/org/adblockplus/sbrowser/contentblocker/engine/Subscription.java | 
| =================================================================== | 
| --- a/adblockplussbrowser/src/org/adblockplus/sbrowser/contentblocker/engine/Subscription.java | 
| +++ b/adblockplussbrowser/src/org/adblockplus/sbrowser/contentblocker/engine/Subscription.java | 
| @@ -27,28 +27,30 @@ import java.io.FileInputStream; | 
| import java.io.FileOutputStream; | 
| import java.io.IOException; | 
| import java.io.StringReader; | 
| import java.net.URL; | 
| import java.nio.charset.StandardCharsets; | 
| import java.security.MessageDigest; | 
| import java.security.NoSuchAlgorithmException; | 
| import java.util.ArrayList; | 
| +import java.util.Arrays; | 
| import java.util.Collection; | 
| import java.util.Collections; | 
| import java.util.HashMap; | 
| import java.util.HashSet; | 
| import java.util.List; | 
| import java.util.Locale; | 
| import java.util.Map; | 
| import java.util.Map.Entry; | 
| import java.util.zip.GZIPInputStream; | 
| import java.util.zip.GZIPOutputStream; | 
|  | 
| import android.text.TextUtils; | 
| +import android.text.format.DateUtils; | 
| import android.util.Log; | 
|  | 
| /** | 
| * Simple subscription representation. | 
| */ | 
| final class Subscription | 
| { | 
| private static final String TAG = Subscription.class.getSimpleName(); | 
| @@ -57,50 +59,43 @@ final class Subscription | 
| public static final String KEY_HTTP_ETAG = "_etag"; | 
| public static final String KEY_HTTP_LAST_MODIFIED = "_last_modified"; | 
| public static final String KEY_UPDATE_TIMESTAMP = "_update_timestamp"; | 
| public static final String KEY_TRIED_UPDATE_TIMESTAMP = "_tried_update_timestamp"; | 
| public static final String KEY_DOWNLOAD_COUNT = "_download_count"; | 
| public static final String KEY_ENABLED = "_enabled"; | 
| public static final String KEY_META_HASH = "_meta_hash"; | 
|  | 
| -  public static final long MINIMAL_DOWNLOAD_INTERVAL = Engine.MILLIS_PER_HOUR / 4; | 
| -  public static final long DOWNLOAD_RETRY_INTERVAL = Engine.MILLIS_PER_HOUR; | 
| - | 
| -  private static final HashSet<String> ALLOWED_META_KEYS = new HashSet<>(); | 
| -  private static final Locale LOCALE_EN = Locale.ENGLISH; | 
| - | 
| -  private final long updateInterval = Engine.MILLIS_PER_DAY | 
| -      + (long) (Engine.MILLIS_PER_HOUR * 8. * Math.random()); | 
| +  private static final long MINIMAL_DOWNLOAD_INTERVAL = DateUtils.HOUR_IN_MILLIS / 4; | 
| +  private static final long DOWNLOAD_RETRY_INTERVAL = DateUtils.HOUR_IN_MILLIS; | 
|  | 
| /** | 
| * List of meta keys that are allowed to import from a downloaded | 
| * subscription. | 
| */ | 
| private static final String[] ALLOWED_META_KEYS_ARRAY = | 
| -  { | 
| -      "checksum", KEY_VERSION, KEY_TITLE, "last modified", "expires", "homepage", "licence" | 
| -  }; | 
| +      { | 
| +          "checksum", KEY_VERSION, KEY_TITLE, "last modified", "expires", "homepage", "licence" | 
| +      }; | 
| +  private static final HashSet<String> ALLOWED_META_KEYS = | 
| +      new HashSet<>(Arrays.asList(ALLOWED_META_KEYS_ARRAY)); | 
| + | 
| +  private static final Locale LOCALE_EN = Locale.ENGLISH; | 
| + | 
| +  private final long updateInterval = DateUtils.DAY_IN_MILLIS | 
| +      + (long) (DateUtils.HOUR_IN_MILLIS * 8. * Math.random()); | 
|  | 
| private final URL url; | 
| private final Type type; | 
| private final HashMap<String, String> meta = new HashMap<>(); | 
| private final HashSet<String> filters = new HashSet<>(); | 
|  | 
| private boolean metaDataValid = true; | 
| private boolean filtersValid = true; | 
|  | 
| -  static | 
| -  { | 
| -    for (final String s : ALLOWED_META_KEYS_ARRAY) | 
| -    { | 
| -      ALLOWED_META_KEYS.add(s); | 
| -    } | 
| -  } | 
| - | 
| /** | 
| * Subscription type. | 
| * | 
| * @author René Jeschke <rene@adblockplus.org> | 
| */ | 
| public enum Type | 
| { | 
| /** | 
| @@ -351,19 +346,19 @@ final class Subscription | 
| return "user:" + subscription.getMeta(KEY_TITLE); | 
| } | 
| return ""; | 
| } | 
|  | 
| private static String byteArrayToHexString(final byte[] array) | 
| { | 
| final StringBuilder sb = new StringBuilder(array.length * 2); | 
| -    for (int i = 0; i < array.length; i++) | 
| +    for (final byte b : array) | 
| { | 
| -      final int value = array[i] & 255; | 
| +      final int value = b & 255; | 
| if (value < 16) | 
| { | 
| sb.append('0'); | 
| } | 
| sb.append(Integer.toHexString(value)); | 
| } | 
| return sb.toString(); | 
| } | 
| @@ -397,33 +392,33 @@ final class Subscription | 
| { | 
| throw new IOException("MD5 is unavailable: " + e.getMessage(), e); | 
| } | 
| } | 
|  | 
| public void serializeMetaData(final File metaFile) throws IOException | 
| { | 
| this.putMeta(KEY_META_HASH, createMetaDataHash(this.meta)); | 
| -    try (final DataOutputStream metaOut = new DataOutputStream(new GZIPOutputStream( | 
| -        new BufferedOutputStream(new FileOutputStream(metaFile))))) | 
| +    try (final DataOutputStream metaOut = new DataOutputStream(new BufferedOutputStream( | 
| +        new GZIPOutputStream(new FileOutputStream(metaFile))))) | 
| { | 
| metaOut.writeUTF(this.url != null ? this.url.toString() : ""); | 
| metaOut.writeInt(this.meta.size()); | 
| for (final Entry<String, String> e : this.meta.entrySet()) | 
| { | 
| metaOut.writeUTF(e.getKey()); | 
| metaOut.writeUTF(e.getValue()); | 
| } | 
| } | 
| } | 
|  | 
| public void serializeFilters(final File filtersFile) throws IOException | 
| { | 
| -    try (final DataOutputStream filtersOut = new DataOutputStream(new GZIPOutputStream( | 
| -        new BufferedOutputStream(new FileOutputStream(filtersFile))))) | 
| +    try (final DataOutputStream filtersOut = new DataOutputStream(new BufferedOutputStream( | 
| +        new GZIPOutputStream(new FileOutputStream(filtersFile))))) | 
| { | 
| filtersOut.writeInt(this.filters.size()); | 
| filtersOut.writeUTF(createFilterHash(new ArrayList<>(this.filters))); | 
| for (final String s : this.filters) | 
| { | 
| final byte[] b = s.getBytes(StandardCharsets.UTF_8); | 
| filtersOut.writeInt(b.length); | 
| filtersOut.write(b); | 
| @@ -435,17 +430,17 @@ final class Subscription | 
| { | 
| this.serializeMetaData(metaFile); | 
| this.serializeFilters(filtersFile); | 
| } | 
|  | 
| public static Subscription deserializeSubscription(final File metaFile) | 
| { | 
| Subscription sub = null; | 
| -    try (final DataInputStream in = new DataInputStream(new GZIPInputStream(new BufferedInputStream( | 
| +    try (final DataInputStream in = new DataInputStream(new BufferedInputStream(new GZIPInputStream( | 
| new FileInputStream(metaFile))))) | 
| { | 
| final String urlString = in.readUTF(); | 
| sub = new Subscription(!TextUtils.isEmpty(urlString) ? new URL(urlString) : null); | 
| sub.metaDataValid = false; | 
| final int numMetaEntries = in.readInt(); | 
| for (int i = 0; i < numMetaEntries; i++) | 
| { | 
| @@ -461,17 +456,17 @@ final class Subscription | 
| } | 
| return sub; | 
| } | 
|  | 
| public void deserializeFilters(final File filtersFile) | 
| { | 
| this.clearFilters(); | 
| this.filtersValid = false; | 
| -    try (final DataInputStream in = new DataInputStream(new GZIPInputStream(new BufferedInputStream( | 
| +    try (final DataInputStream in = new DataInputStream(new BufferedInputStream(new GZIPInputStream( | 
| new FileInputStream(filtersFile))))) | 
| { | 
| final int numFilters = in.readInt(); | 
| final String filtersHash = in.readUTF(); | 
| for (int i = 0; i < numFilters; i++) | 
| { | 
| final int length = in.readInt(); | 
| final byte[] b = new byte[length]; | 
|  |