]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
Switch to EasyList block lists. https://redmine.stoutner.com/issues/136.
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / MainWebViewActivity.java
index cfe93f2740163d27a76435965151891ecfe69404..01d1f8b4a3acc1cc94149251c84f14437c90e884 100644 (file)
@@ -22,7 +22,6 @@
 package com.stoutner.privacybrowser.activities;
 
 import android.annotation.SuppressLint;
-import android.app.Activity;
 import android.app.DialogFragment;
 import android.app.DownloadManager;
 import android.content.BroadcastReceiver;
@@ -53,7 +52,6 @@ import android.support.design.widget.CoordinatorLayout;
 import android.support.design.widget.FloatingActionButton;
 import android.support.design.widget.NavigationView;
 import android.support.design.widget.Snackbar;
-import android.support.v4.app.ActivityCompat;
 import android.support.v4.content.ContextCompat;
 // `ShortcutInfoCompat`, `ShortcutManagerCompat`, and `IconCompat` can be switched to the non-compat version once API >= 26.
 import android.support.v4.content.pm.ShortcutInfoCompat;
@@ -71,7 +69,6 @@ import android.text.Editable;
 import android.text.Spanned;
 import android.text.TextWatcher;
 import android.text.style.ForegroundColorSpan;
-import android.util.Log;
 import android.util.Patterns;
 import android.view.ContextMenu;
 import android.view.GestureDetector;
@@ -118,31 +115,29 @@ import com.stoutner.privacybrowser.dialogs.HttpAuthenticationDialog;
 import com.stoutner.privacybrowser.dialogs.PinnedSslCertificateMismatchDialog;
 import com.stoutner.privacybrowser.dialogs.UrlHistoryDialog;
 import com.stoutner.privacybrowser.dialogs.ViewSslCertificateDialog;
+import com.stoutner.privacybrowser.helpers.BlockListHelper;
 import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper;
 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
 import com.stoutner.privacybrowser.helpers.OrbotProxyHelper;
 import com.stoutner.privacybrowser.dialogs.DownloadFileDialog;
 import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog;
 
-import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.regex.Pattern;
 
 // We need to use AppCompatActivity from android.support.v7.app.AppCompatActivity to have access to the SupportActionBar until the minimum API is >= 21.
 public class MainWebViewActivity extends AppCompatActivity implements AddDomainDialog.AddDomainListener, CreateBookmarkDialog.CreateBookmarkListener,
@@ -179,9 +174,6 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
     // `appliedUserAgentString` is public static so it can be accessed from `ViewSourceActivity`.  It is also used in `applyDomainSettings()`.
     public static String appliedUserAgentString;
 
-    // `displayWebpageImagesBoolean` is public static so it can be accessed from `DomainSettingsFragment`.  It is also used in `applyAppSettings()` and `applyDomainSettings()`.
-    public static boolean displayWebpageImagesBoolean;
-
     // `reloadOnRestart` is public static so it can be accessed from `SettingsFragment`.  It is also used in `onRestart()`
     public static boolean reloadOnRestart;
 
@@ -191,8 +183,11 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
     // `restartFromBookmarksActivity` is public static so it can be accessed from `BookmarksActivity`.  It is also used in `onRestart()`.
     public static boolean restartFromBookmarksActivity;
 
-    // `easyListVersion` is public static so it can be accessed from `AboutTabFragment`.  It is also used in `onCreate()`.
+    // The block list versions are public static so they can be accessed from `AboutTabFragment`.  They are also used in `onCreate()`.
     public static String easyListVersion;
+    public static String easyPrivacyVersion;
+    public static String fanboyAnnoyanceVersion;
+    public static String fanboySocialVersion;
 
     // `currentBookmarksFolder` is public static so it can be accessed from `BookmarksActivity`.  It is also used in `onCreate()`, `onBackPressed()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`,
     // `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`.
@@ -270,14 +265,20 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
     // `swipeToRefreshEnabled` is used in `onPrepareOptionsMenu()` and `applyAppSettings()`.
     private boolean swipeToRefreshEnabled;
 
+    // `displayWebpageImagesBoolean` is used in `applyAppSettings()` and `applyDomainSettings()`.
+    private boolean displayWebpageImagesBoolean;
+
     // 'homepage' is used in `onCreate()`, `onNavigationItemSelected()`, and `applyAppSettings()`.
     private String homepage;
 
     // `searchURL` is used in `loadURLFromTextBox()` and `applyAppSettings()`.
     private String searchURL;
 
-    // `adBlockerEnabled` is used in `onCreate()` and `applyAppSettings()`.
-    private boolean adBlockerEnabled;
+    // The block list variables are used in `onCreate()` and `applyAppSettings()`.
+    private boolean easyListEnabled;
+    private boolean easyPrivacyEnabled;
+    private boolean fanboyAnnoyanceListEnabled;
+    private boolean fanboySocialBlockingListEnabled;
 
     // `privacyBrowserRuntime` is used in `onCreate()`, `onOptionsItemSelected()`, and `applyAppSettings()`.
     private Runtime privacyBrowserRuntime;
@@ -408,744 +409,20 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
         // Run the default commands.
         super.onCreate(savedInstanceState);
 
-        Log.i("BlockLists", "Begin populating block lists.");
-
-        // Initialize the block lists.
-        List<String> mainWhiteList = new LinkedList<>();
-        List<String[]> multiEntryWhiteList = new LinkedList<>();
-        List<String> mainBlockList = new LinkedList<>();
-        List<String> initialBlockList = new LinkedList<>();
-        List<String> finalBlockList = new LinkedList<>();
-        List<String[]> multiEntryBlockList = new LinkedList<>();
-        List<String[]> multiEntryInitialBlockList = new LinkedList<>();
-        List<String[]> multiEntryFinalBlockList = new LinkedList<>();
-        List<String[]> domainBlockList = new LinkedList<>();
-        List<String[]> domainInitialBlockList = new LinkedList<>();
-        List<String[]> domainFinalBlockList = new LinkedList<>();
-        List<String[]> domainMultiEntryBlockList = new LinkedList<>();
-        List<String[]> domainRegularExpressionBlockList = new LinkedList<>();
-        List<String> regularExpressionBlockList = new LinkedList<>();
-
-        // Populate the block lists.
-        try {
-            // Load `easylist.txt` into a `BufferedReader`.
-            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(getAssets().open("easylist.txt")));
-
-            // Create a string for storing the block list entries.
-            String blockListEntry;
-
-            // Parse EasyList.
-            while ((blockListEntry = bufferedReader.readLine()) != null) {
-                //noinspection StatementWithEmptyBody
-                if (blockListEntry.contains("##") || blockListEntry.contains("#?#") || blockListEntry.contains("#@#") || blockListEntry.startsWith("[")) {
-                    // Entries that contain `##`, `#?#`, and `#@#` are for hiding elements in the main page's HTML.  Entries that start with `[` describe the AdBlock compatibility level.
-
-                    // Do nothing.  Privacy Browser does not currently use these entries.
-
-                    //Log.i("BlackLists", "Not added: " + adBlockerEntry);
-                } else if (blockListEntry.startsWith("!")){  //  Entries that begin with `!` are comments.
-                    if (blockListEntry.startsWith("! Version:")) {
-                        // Store the EasyList version number.
-                        easyListVersion = blockListEntry.substring(11);
-                    }
-
-                    //Log.i("BlackLists", "Not added: " + adBlockerEntry);
-                } else if (blockListEntry.startsWith("@@")) {  // Entries that begin with `@@` are excludes (whitelists).
-                    // mainWhiteList.add(blockListEntry.substring(2));
-
-                    //Log.i("BlockLists", "Main white list added: " + blockListEntry.substring(2, blockListEntry.length()));
-                } else if (blockListEntry.endsWith("|")){  // Entries that end with `|` match against the end of the URL.
-                    // Strip out the final "|"
-                    blockListEntry = blockListEntry.substring(0, blockListEntry.length() - 1);
-
-                    // Strip out any initial `||`.  They are redundant in this case because the block list entry is being matched against the end of the URL.
-                    if (blockListEntry.startsWith("||")) {
-                        blockListEntry = blockListEntry.substring(2);
-                    }
-
-                    if (blockListEntry.contains("*")) {
-                        int wildcardIndex = blockListEntry.indexOf("*");
-
-                        String firstEntry = blockListEntry.substring(0, wildcardIndex);
-                        String secondEntry = blockListEntry.substring(wildcardIndex + 1);
-
-                        if (firstEntry.endsWith("^")) {
-                            String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1);
-
-                            String firstEntry1 = firstEntryBase + ":";
-                            String firstEntry2 = firstEntryBase + "/";
-                            String firstEntry3 = firstEntryBase + "?";
-                            String firstEntry4 = firstEntryBase + "=";
-                            String firstEntry5 = firstEntryBase + "&";
-
-                            String[] doubleEntry1 = {firstEntry1, secondEntry};
-                            String[] doubleEntry2 = {firstEntry2, secondEntry};
-                            String[] doubleEntry3 = {firstEntry3, secondEntry};
-                            String[] doubleEntry4 = {firstEntry4, secondEntry};
-                            String[] doubleEntry5 = {firstEntry5, secondEntry};
-
-                            multiEntryFinalBlockList.add(doubleEntry1);
-                            multiEntryFinalBlockList.add(doubleEntry2);
-                            multiEntryFinalBlockList.add(doubleEntry3);
-                            multiEntryFinalBlockList.add(doubleEntry4);
-                            multiEntryFinalBlockList.add(doubleEntry5);
-
-                            //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry1 + " , " + secondEntry);
-                            //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry2 + " , " + secondEntry);
-                            //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry3 + " , " + secondEntry);
-                            //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry4 + " , " + secondEntry);
-                            //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry5 + " , " + secondEntry);
-                        } else {
-                            String[] doubleEntry = {firstEntry, secondEntry};
-
-                            multiEntryFinalBlockList.add(doubleEntry);
-
-                            //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry + " , " + secondEntry);
-                        }
-                    } else {
-                        finalBlockList.add(blockListEntry);
-
-                        //Log.i("BlockLists", "Final block list added: " + blockListEntry);
-                    }
-                } else if (blockListEntry.contains("$")) {  // Entries that contain `$` use filter options.
-                    // Strip out any initial `||`.  These will be treated like any other entry.
-                    if (blockListEntry.startsWith("||")) {
-                        blockListEntry = blockListEntry.substring(2);
-                    }
-
-                    if (blockListEntry.contains("third-party")) {
-                        // Log.i("BlockLists", "Not added: " + blockListEntry);
-                    } else if (blockListEntry.substring(blockListEntry.indexOf("$")).contains("domain")) {
-                        if (blockListEntry.contains("~")) {  // Whitelist.
-
-                        } else {
-                            // Separate the filters.
-                            String entry = blockListEntry.substring(0, blockListEntry.indexOf("$"));
-                            String filters = blockListEntry.substring(blockListEntry.indexOf("$") + 1);
-                            String domains = filters.substring(filters.indexOf("domain=") + 7);
-
-                            // Only process the block list item if the entry is not null.  Some lines in EasyList begin with `$websocket`, which create a null entry.
-                            if (!entry.equals("")) {
-                                do {
-                                    String domain;
-
-                                    if (domains.contains("|")) {
-                                        // Get the first domain.
-                                        domain = domains.substring(0, domains.indexOf("|"));
-
-                                        // Remove the first domain from the list.
-                                        domains = domains.substring(domains.indexOf("|") + 1);
-                                    } else {
-                                        domain = domains;
-                                    }
-
-                                    if (entry.contains("*")) {
-                                        int wildcardIndex = entry.indexOf("*");
-
-                                        String firstEntry = entry.substring(0, wildcardIndex);
-                                        String secondEntry = entry.substring(wildcardIndex + 1);
-
-                                        if (firstEntry.endsWith("^")) {
-                                            String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1);
-
-                                            String firstEntry1 = firstEntryBase + ":";
-                                            String firstEntry2 = firstEntryBase + "/";
-                                            String firstEntry3 = firstEntryBase + "?";
-                                            String firstEntry4 = firstEntryBase + "=";
-                                            String firstEntry5 = firstEntryBase + "&";
-
-                                            String[] domainDoubleEntry1 = {domain, firstEntry1, secondEntry};
-                                            String[] domainDoubleEntry2 = {domain, firstEntry2, secondEntry};
-                                            String[] domainDoubleEntry3 = {domain, firstEntry3, secondEntry};
-                                            String[] domainDoubleEntry4 = {domain, firstEntry4, secondEntry};
-                                            String[] domainDoubleEntry5 = {domain, firstEntry5, secondEntry};
-
-                                            domainMultiEntryBlockList.add(domainDoubleEntry1);
-                                            domainMultiEntryBlockList.add(domainDoubleEntry2);
-                                            domainMultiEntryBlockList.add(domainDoubleEntry3);
-                                            domainMultiEntryBlockList.add(domainDoubleEntry4);
-                                            domainMultiEntryBlockList.add(domainDoubleEntry5);
-
-                                            //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry1 + " , " + secondEntry);
-                                            //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry2 + " , " + secondEntry);
-                                            //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry3 + " , " + secondEntry);
-                                            //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry4 + " , " + secondEntry);
-                                            //Log.i("BlockLists", "Domain ^ double entry block list added: " + domain + " , " + firstEntry5 + " , " + secondEntry);
-                                        } else {
-                                            String[] domainDoubleEntry = {domain, firstEntry, secondEntry};
-
-                                            domainMultiEntryBlockList.add(domainDoubleEntry);
-
-                                            //Log.i("BlockLists", "Domain double entry block list added: " + domain + " , " + firstEntry + " , " + secondEntry);
-                                        }
-                                    } else if (entry.endsWith("^")) {
-                                        String entryBase = entry.substring(0, entry.length() - 1);
-
-                                        String entry1 = entryBase + ":";
-                                        String entry2 = entryBase + "/";
-                                        String entry3 = entryBase + "?";
-                                        String entry4 = entryBase + "=";
-                                        String entry5 = entryBase + "&";
-
-                                        String[] domainEntry1 = {domain, entry1};
-                                        String[] domainEntry2 = {domain, entry2};
-                                        String[] domainEntry3 = {domain, entry3};
-                                        String[] domainEntry4 = {domain, entry4};
-                                        String[] domainEntry5 = {domain, entry5};
-
-                                        domainBlockList.add(domainEntry1);
-                                        domainBlockList.add(domainEntry2);
-                                        domainBlockList.add(domainEntry3);
-                                        domainBlockList.add(domainEntry4);
-                                        domainBlockList.add(domainEntry5);
-
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry1);
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry2);
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry3);
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry4);
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry5);
-                                    } else if (entry.startsWith("^")) {
-                                        String entryBase = entry.substring(1);
-
-                                        String entry1 = ":" + entryBase;
-                                        String entry2 = ":" + entryBase;
-                                        String entry3 = ":" + entryBase;
-                                        String entry4 = ":" + entryBase;
-                                        String entry5 = ":" + entryBase;
-
-                                        String[] domainEntry1 = {domain, entry1};
-                                        String[] domainEntry2 = {domain, entry2};
-                                        String[] domainEntry3 = {domain, entry3};
-                                        String[] domainEntry4 = {domain, entry4};
-                                        String[] domainEntry5 = {domain, entry5};
-
-                                        domainBlockList.add(domainEntry1);
-                                        domainBlockList.add(domainEntry2);
-                                        domainBlockList.add(domainEntry3);
-                                        domainBlockList.add(domainEntry4);
-                                        domainBlockList.add(domainEntry5);
-
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry1);
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry2);
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry3);
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry4);
-                                        //Log.i("BlockLists", "Domain ^ block list added: " + domain + " , " + entry5);
-                                    } else if (entry.startsWith("|")) {
-                                        // Remove the initial `|`;
-                                        String entryBase = entry.substring(1);
-
-                                        //noinspection StatementWithEmptyBody
-                                        if (entryBase.equals("http://") || entryBase.equals("https://")) {
-                                            // Do nothing.  These entries will entirely block the website.
-                                            // Often the original entry blocks `$script` but Privacy Browser does not currently differentiate between scripts and other entries.
-                                        } else {
-                                            String[] domainEntry = {domain, entryBase};
-
-                                            domainInitialBlockList.add(domainEntry);
-
-                                            //Log.i("BlockLists", "Domain initial block list added: " + domain + " , " + entryBase);
-                                        }
-                                    } else if (entry.endsWith("|")) {
-                                        // Remove the final `|`.
-                                        String entryBase = entry.substring(0, entry.length() - 1);
-
-                                        String[] domainEntry = {domain, entryBase};
-
-                                        domainFinalBlockList.add(domainEntry);
-
-                                        Log.i("BlockLists", "Domain final block list added: " + domain + " , " + entryBase);
-                                    } else if (entry.contains("\\")) {
-                                        String[] domainEntry = {domain, entry};
-
-                                        domainRegularExpressionBlockList.add(domainEntry);
-
-                                        // Log.i("BlockLists", "Domain regular expression block list added: " + domain + " , " + entry);
-                                    } else {
-                                        String[] domainEntry = {domain, entry};
-
-                                        domainBlockList.add(domainEntry);
-
-                                        //Log.i("BlockLists", "Domain block list added: " + domain + " , " + entry);
-                                    }
-                                } while (domains.contains("|"));
-                            }
-                        }
-                    } else if (blockListEntry.contains("~")) {  // Whitelist entries.
-                        // Remove the filter options.
-                        blockListEntry = blockListEntry.substring(0, blockListEntry.indexOf("$"));
-
-                        // Strip any trailing `*`.
-                        if (blockListEntry.endsWith("*")) {
-                            blockListEntry = blockListEntry.substring(0, blockListEntry.length() -1);
-                        }
-
-                        if (blockListEntry.contains("*")) {
-                            int wildcardIndex = blockListEntry.indexOf("*");
-
-                            String firstEntry = blockListEntry.substring(0, wildcardIndex);
-                            String secondEntry = blockListEntry.substring(wildcardIndex + 1);
-
-                            if (firstEntry.endsWith("^")) {
-                                String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1);
-
-                                String firstEntry1 = firstEntryBase + ":";
-                                String firstEntry2 = firstEntryBase + "/";
-                                String firstEntry3 = firstEntryBase + "?";
-                                String firstEntry4 = firstEntryBase + "=";
-                                String firstEntry5 = firstEntryBase + "&";
-
-                                String[] doubleEntry1 = {firstEntry1, secondEntry};
-                                String[] doubleEntry2 = {firstEntry2, secondEntry};
-                                String[] doubleEntry3 = {firstEntry3, secondEntry};
-                                String[] doubleEntry4 = {firstEntry4, secondEntry};
-                                String[] doubleEntry5 = {firstEntry5, secondEntry};
-
-                                multiEntryWhiteList.add(doubleEntry1);
-                                multiEntryWhiteList.add(doubleEntry2);
-                                multiEntryWhiteList.add(doubleEntry3);
-                                multiEntryWhiteList.add(doubleEntry4);
-                                multiEntryWhiteList.add(doubleEntry5);
-
-                                //Log.i("BlockLists", "Multi entry white list added: " + firstEntry1 + " , " + secondEntry);
-                                //Log.i("BlockLists", "Multi entry white list added: " + firstEntry2 + " , " + secondEntry);
-                                //Log.i("BlockLists", "Multi entry white list added: " + firstEntry3 + " , " + secondEntry);
-                                //Log.i("BlockLists", "Multi entry white list added: " + firstEntry4 + " , " + secondEntry);
-                                //Log.i("BlockLists", "Multi entry white list added: " + firstEntry5 + " , " + secondEntry);
-                            } else {
-                                String[] doubleEntry = {firstEntry, secondEntry};
-
-                                multiEntryWhiteList.add(doubleEntry);
-
-                                //Log.i("BlockLists", "Multi entry white list added: " + firstEntry + " , " + secondEntry);
-                            }
-                        } else {
-                            if (blockListEntry.endsWith("^")) {
-                                String blockListEntryBase = blockListEntry.substring(0, blockListEntry.length() - 1);
-
-                                String blockListEntry1 = blockListEntryBase + ":";
-                                String blockListEntry2 = blockListEntryBase + "/";
-                                String blockListEntry3 = blockListEntryBase + "?";
-                                String blockListEntry4 = blockListEntryBase + "=";
-                                String blockListEntry5 = blockListEntryBase + "&";
-
-                                mainWhiteList.add(blockListEntry1);
-                                mainWhiteList.add(blockListEntry2);
-                                mainWhiteList.add(blockListEntry3);
-                                mainWhiteList.add(blockListEntry4);
-                                mainWhiteList.add(blockListEntry5);
-
-                                // Log.i("BlockLists", "Main white list added: " + blockListEntry1);
-                                // Log.i("BlockLists", "Main white list added: " + blockListEntry2);
-                                // Log.i("BlockLists", "Main white list added: " + blockListEntry3);
-                                // Log.i("BlockLists", "Main white list added: " + blockListEntry4);
-                                // Log.i("BlockLists", "Main white list added: " + blockListEntry5);
-                            } else {
-                                mainWhiteList.add(blockListEntry);
-
-                                // Log.i("BlockLists", "Main white list added: " + blockListEntry);
-                            }
-                        }
-                    } else if (blockListEntry.contains("\\")) {  // Regular expressions.
-                        // Remove the filter options.
-                        blockListEntry = blockListEntry.substring(0, blockListEntry.indexOf("$"));
-
-                        regularExpressionBlockList.add(blockListEntry);
-
-                        //Log.i("BlockLists", "Regular expression list added: " + blockListEntry);
-                    } else {
-                        // Remove the filter options.
-                        blockListEntry = blockListEntry.substring(0, blockListEntry.indexOf("$"));
-
-                        // Strip any trailing `*` or `^`.  Many of these entries have `^$`, which seem redundant for the purposes of Privacy Browser.
-                        if (blockListEntry.endsWith("*") || blockListEntry.endsWith("^")) {
-                            blockListEntry = blockListEntry.substring(0, blockListEntry.length() - 1);
-                        }
-
-                        if (blockListEntry.contains("*")) {  // Use a multi entry list.
-                            int wildcardIndex = blockListEntry.indexOf("*");
-
-                            String firstEntry = blockListEntry.substring(0, wildcardIndex);
-                            String secondEntry = blockListEntry.substring(wildcardIndex + 1);
-
-                            // Remove `.*` if it appears at the beginning of the second entry.
-                            if (secondEntry.startsWith(".*")) {
-                                secondEntry = secondEntry.substring(2);
-                            }
-
-                            // Create a third entry if required.
-                            if (secondEntry.contains("*")) {
-                                wildcardIndex = secondEntry.indexOf("*");
-
-                                String thirdEntry = secondEntry.substring(wildcardIndex + 1);
-                                secondEntry = secondEntry.substring(0, wildcardIndex);
-
-                                if (firstEntry.endsWith("^")) {
-                                    String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1);
-
-                                    String firstEntry1 = firstEntryBase + ":";
-                                    String firstEntry2 = firstEntryBase + "/";
-                                    String firstEntry3 = firstEntryBase + "?";
-                                    String firstEntry4 = firstEntryBase + "=";
-                                    String firstEntry5 = firstEntryBase + "&";
-
-                                    if (thirdEntry.endsWith("|")) {
-                                        thirdEntry = thirdEntry.substring(0, thirdEntry.length() - 1);
-
-                                        String[] tripleEntry1 = {firstEntry1, secondEntry, thirdEntry};
-                                        String[] tripleEntry2 = {firstEntry2, secondEntry, thirdEntry};
-                                        String[] tripleEntry3 = {firstEntry3, secondEntry, thirdEntry};
-                                        String[] tripleEntry4 = {firstEntry4, secondEntry, thirdEntry};
-                                        String[] tripleEntry5 = {firstEntry5, secondEntry, thirdEntry};
-
-                                        multiEntryFinalBlockList.add(tripleEntry1);
-                                        multiEntryFinalBlockList.add(tripleEntry2);
-                                        multiEntryFinalBlockList.add(tripleEntry3);
-                                        multiEntryFinalBlockList.add(tripleEntry4);
-                                        multiEntryFinalBlockList.add(tripleEntry5);
-
-                                        //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry1 + " , " + secondEntry + " , " + thirdEntry);
-                                        //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry2 + " , " + secondEntry + " , " + thirdEntry);
-                                        //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry3 + " , " + secondEntry + " , " + thirdEntry);
-                                        //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry4 + " , " + secondEntry + " , " + thirdEntry);
-                                        //Log.i("BlockLists", "Multi entry final tripple block list added: " + firstEntry5 + " , " + secondEntry + " , " + thirdEntry);
-                                    } else {
-                                        String[] tripleEntry1 = {firstEntry1, secondEntry, thirdEntry};
-                                        String[] tripleEntry2 = {firstEntry2, secondEntry, thirdEntry};
-                                        String[] tripleEntry3 = {firstEntry3, secondEntry, thirdEntry};
-                                        String[] tripleEntry4 = {firstEntry4, secondEntry, thirdEntry};
-                                        String[] tripleEntry5 = {firstEntry5, secondEntry, thirdEntry};
-
-                                        multiEntryBlockList.add(tripleEntry1);
-                                        multiEntryBlockList.add(tripleEntry2);
-                                        multiEntryBlockList.add(tripleEntry3);
-                                        multiEntryBlockList.add(tripleEntry4);
-                                        multiEntryBlockList.add(tripleEntry5);
-
-                                        //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry1 + " , " + secondEntry + " , " + thirdEntry);
-                                        //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry2 + " , " + secondEntry + " , " + thirdEntry);
-                                        //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry3 + " , " + secondEntry + " , " + thirdEntry);
-                                        //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry4 + " , " + secondEntry + " , " + thirdEntry);
-                                        //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry5 + " , " + secondEntry + " , " + thirdEntry);
-                                    }
-                                } else {
-                                    String[] tripleEntry = {firstEntry, secondEntry, thirdEntry};
-
-                                    multiEntryBlockList.add(tripleEntry);
-
-                                    // Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry + " , " + secondEntry + " , " + thirdEntry);
-                                }
-                            } else {  // This is a double entry.
-                                if (firstEntry.startsWith("|")) {
-                                    String[] doubleEntry = {firstEntry.substring(1), secondEntry};
-
-                                    multiEntryInitialBlockList.add(doubleEntry);
-
-                                    //Log.i("BlockLists", "Multi entry initial block list added: " + firstEntry.substring(1) + " , " + secondEntry);
-                                } else if (firstEntry.startsWith("^")) {
-                                    String firstEntryBase = firstEntry.substring(1);
-
-                                    String firstEntry1 = ":" + firstEntryBase;
-                                    String firstEntry2 = "/" + firstEntryBase;
-                                    String firstEntry3 = "?" + firstEntryBase;
-                                    String firstEntry4 = "=" + firstEntryBase;
-                                    String firstEntry5 = "&" + firstEntryBase;
-
-                                    String[] doubleEntry1 = {firstEntry1, secondEntry};
-                                    String[] doubleEntry2 = {firstEntry2, secondEntry};
-                                    String[] doubleEntry3 = {firstEntry3, secondEntry};
-                                    String[] doubleEntry4 = {firstEntry4, secondEntry};
-                                    String[] doubleEntry5 = {firstEntry5, secondEntry};
-
-                                    multiEntryBlockList.add(doubleEntry1);
-                                    multiEntryBlockList.add(doubleEntry2);
-                                    multiEntryBlockList.add(doubleEntry3);
-                                    multiEntryBlockList.add(doubleEntry4);
-                                    multiEntryBlockList.add(doubleEntry5);
-
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry1 + " , " + secondEntry);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry2 + " , " + secondEntry);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry3 + " , " + secondEntry);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry4 + " , " + secondEntry);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry5 + " , " + secondEntry);
-                                } else if (firstEntry.endsWith("^")) {
-                                    String firstEntryBase = firstEntry.substring(0, firstEntry.length() - 1);
-
-                                    String firstEntry1 = firstEntryBase + ":";
-                                    String firstEntry2 = firstEntryBase + "/";
-                                    String firstEntry3 = firstEntryBase + "?";
-                                    String firstEntry4 = firstEntryBase + "=";
-                                    String firstEntry5 = firstEntryBase + "&";
-
-                                    String[] doubleEntry1 = {firstEntry1, secondEntry};
-                                    String[] doubleEntry2 = {firstEntry2, secondEntry};
-                                    String[] doubleEntry3 = {firstEntry3, secondEntry};
-                                    String[] doubleEntry4 = {firstEntry4, secondEntry};
-                                    String[] doubleEntry5 = {firstEntry5, secondEntry};
-
-                                    multiEntryBlockList.add(doubleEntry1);
-                                    multiEntryBlockList.add(doubleEntry2);
-                                    multiEntryBlockList.add(doubleEntry3);
-                                    multiEntryBlockList.add(doubleEntry4);
-                                    multiEntryBlockList.add(doubleEntry5);
-
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry1 + " , " + secondEntry);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry2 + " , " + secondEntry);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry3 + " , " + secondEntry);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry4 + " , " + secondEntry);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry5 + " , " + secondEntry);
-                                } else if (secondEntry.startsWith("^")) {
-                                    String secondEntryBase = secondEntry.substring(1);
-
-                                    String secondEntry1 = ":" + secondEntryBase;
-                                    String secondEntry2 = "/" + secondEntryBase;
-                                    String secondEntry3 = "?" + secondEntryBase;
-                                    String secondEntry4 = "=" + secondEntryBase;
-                                    String secondEntry5 = "&" + secondEntryBase;
-
-                                    String[] doubleEntry1 = {firstEntry, secondEntry1};
-                                    String[] doubleEntry2 = {firstEntry, secondEntry2};
-                                    String[] doubleEntry3 = {firstEntry, secondEntry3};
-                                    String[] doubleEntry4 = {firstEntry, secondEntry4};
-                                    String[] doubleEntry5 = {firstEntry, secondEntry5};
-
-                                    multiEntryBlockList.add(doubleEntry1);
-                                    multiEntryBlockList.add(doubleEntry2);
-                                    multiEntryBlockList.add(doubleEntry3);
-                                    multiEntryBlockList.add(doubleEntry4);
-                                    multiEntryBlockList.add(doubleEntry5);
-
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry1);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry2);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry3);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry4);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry5);
-                                } else if (secondEntry.endsWith("^")) {
-                                    String secondEntryBase = secondEntry.substring(0, secondEntry.length() - 1);
-
-                                    String secondEntry1 = secondEntryBase + ":";
-                                    String secondEntry2 = secondEntryBase + "/";
-                                    String secondEntry3 = secondEntryBase + "?";
-                                    String secondEntry4 = secondEntryBase + "=";
-                                    String secondEntry5 = secondEntryBase + "&";
-
-                                    String[] doubleEntry1 = {firstEntry, secondEntry1};
-                                    String[] doubleEntry2 = {firstEntry, secondEntry2};
-                                    String[] doubleEntry3 = {firstEntry, secondEntry3};
-                                    String[] doubleEntry4 = {firstEntry, secondEntry4};
-                                    String[] doubleEntry5 = {firstEntry, secondEntry5};
-
-                                    String[] doubleEntryFinal = {firstEntry, secondEntryBase};
-
-                                    multiEntryBlockList.add(doubleEntry1);
-                                    multiEntryBlockList.add(doubleEntry2);
-                                    multiEntryBlockList.add(doubleEntry3);
-                                    multiEntryBlockList.add(doubleEntry4);
-                                    multiEntryBlockList.add(doubleEntry5);
-
-                                    multiEntryFinalBlockList.add(doubleEntryFinal);
-
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry1);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry2);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry3);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry4);
-                                    //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry5);
-
-                                    //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry + " , " + secondEntryBase);
-                                } else {
-                                    String[] doubleEntry = {firstEntry, secondEntry};
-
-                                    multiEntryBlockList.add(doubleEntry);
-
-                                    //Log.i("BlockLists", "Multi entry block list added: " + firstEntry + " , " + secondEntry);
-                                }
-                            }
-                        } else if (blockListEntry.startsWith("|")) {  // Populate the initial block list.
-                            // Strip the initial `|`.
-                            blockListEntry = blockListEntry.substring(1);
-
-                            // Populate the initial block list.
-                            initialBlockList.add(blockListEntry);
-
-                            //Log.i("BlockLists", "Initial block list added: " + blockListEntry);
-                        } else {  // Populate the main block list.
-                            mainBlockList.add(blockListEntry);
-
-                            //Log.i("BlockLists", "Main block list added: " + blockListEntry);
-                        }
-                    }
-                } else {  // Populate the standard lists.
-                    // Strip out any initial `||`.  These will be treated like any other entry.
-                    if (blockListEntry.startsWith("||")) {
-                        blockListEntry = blockListEntry.substring(2);
-                    }
-
-                    // Strip out any initial `*`.
-                    if (blockListEntry.startsWith("*")) {
-                        blockListEntry = blockListEntry.substring(1);
-                    }
-
-                    // Strip out any trailing `*`.
-                    if (blockListEntry.endsWith("*")) {
-                        blockListEntry = blockListEntry.substring(0, blockListEntry.length() - 1);
-                    }
-
-                    if (blockListEntry.contains("*")) {  // Entries that contain a `*` in the middle have to be treated specially.
-                        int wildcardIndex = blockListEntry.indexOf("*");
-
-                        String firstEntry = blockListEntry.substring(0, wildcardIndex);
-                        String secondEntry = blockListEntry.substring(wildcardIndex + 1);
-
-                        // Remove `.*` if it appears at the beginning of the second entry.
-                        if (secondEntry.startsWith(".*")) {
-                            secondEntry = secondEntry.substring(2);
-                        }
-
-                        // Create a third entry if required.
-                        if (secondEntry.contains("*")) {
-                            wildcardIndex = secondEntry.indexOf("*");
-
-                            String thirdEntry = secondEntry.substring(wildcardIndex + 1);
-                            secondEntry = secondEntry.substring(0, wildcardIndex);
-
-                            String[] tripleEntry = {firstEntry, secondEntry, thirdEntry};
-
-                            multiEntryBlockList.add(tripleEntry);
-
-                            //Log.i("BlockLists", "Multi entry tripple block list added: " + firstEntry + " , " + secondEntry + " , " + thirdEntry);
-                        } else {
-                            if (firstEntry.startsWith("|")) {
-                                String[] doubleEntry = {firstEntry.substring(1), secondEntry};
-
-                                multiEntryInitialBlockList.add(doubleEntry);
-
-                                //Log.i("BlockLists", "Multi entry initial block list added: " + firstEntry.substring(1) + " , " + secondEntry);
-                            } else if (firstEntry.startsWith("^")) {
-                                String firstEntryBase = firstEntry.substring(1);
-
-                                String firstEntry1 = ":" + firstEntryBase;
-                                String firstEntry2 = "/" + firstEntryBase;
-                                String firstEntry3 = "?" + firstEntryBase;
-                                String firstEntry4 = "=" + firstEntryBase;
-                                String firstEntry5 = "&" + firstEntryBase;
-
-                                String[] doubleEntry1 = {firstEntry1, secondEntry};
-                                String[] doubleEntry2 = {firstEntry2, secondEntry};
-                                String[] doubleEntry3 = {firstEntry3, secondEntry};
-                                String[] doubleEntry4 = {firstEntry4, secondEntry};
-                                String[] doubleEntry5 = {firstEntry5, secondEntry};
-
-                                multiEntryBlockList.add(doubleEntry1);
-                                multiEntryBlockList.add(doubleEntry2);
-                                multiEntryBlockList.add(doubleEntry3);
-                                multiEntryBlockList.add(doubleEntry4);
-                                multiEntryBlockList.add(doubleEntry5);
-
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry1 + " , " + secondEntry);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry2 + " , " + secondEntry);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry3 + " , " + secondEntry);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry4 + " , " + secondEntry);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry5 + " , " + secondEntry);
-                            } else if (secondEntry.startsWith("^")) {
-                                String secondEntryBase = secondEntry.substring(1);
-
-                                String secondEntry1 = ":" + secondEntryBase;
-                                String secondEntry2 = "/" + secondEntryBase;
-                                String secondEntry3 = "?" + secondEntryBase;
-                                String secondEntry4 = "=" + secondEntryBase;
-                                String secondEntry5 = "&" + secondEntryBase;
-
-                                String[] doubleEntry1 = {firstEntry, secondEntry1};
-                                String[] doubleEntry2 = {firstEntry, secondEntry2};
-                                String[] doubleEntry3 = {firstEntry, secondEntry3};
-                                String[] doubleEntry4 = {firstEntry, secondEntry4};
-                                String[] doubleEntry5 = {firstEntry, secondEntry5};
-
-                                multiEntryBlockList.add(doubleEntry1);
-                                multiEntryBlockList.add(doubleEntry2);
-                                multiEntryBlockList.add(doubleEntry3);
-                                multiEntryBlockList.add(doubleEntry4);
-                                multiEntryBlockList.add(doubleEntry5);
-
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry1);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry2);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry3);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry4);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry5);
-                            } else if (secondEntry.endsWith("^")) {
-                                String secondEntryBase = secondEntry.substring(0, secondEntry.length() - 1);
-
-                                String secondEntry1 = secondEntryBase + ":";
-                                String secondEntry2 = secondEntryBase + "/";
-                                String secondEntry3 = secondEntryBase + "?";
-                                String secondEntry4 = secondEntryBase + "=";
-                                String secondEntry5 = secondEntryBase + "&";
-
-                                String[] doubleEntry1 = {firstEntry, secondEntry1};
-                                String[] doubleEntry2 = {firstEntry, secondEntry2};
-                                String[] doubleEntry3 = {firstEntry, secondEntry3};
-                                String[] doubleEntry4 = {firstEntry, secondEntry4};
-                                String[] doubleEntry5 = {firstEntry, secondEntry5};
-
-                                String[] doubleEntryFinal = {firstEntry, secondEntryBase};
-
-                                multiEntryBlockList.add(doubleEntry1);
-                                multiEntryBlockList.add(doubleEntry2);
-                                multiEntryBlockList.add(doubleEntry3);
-                                multiEntryBlockList.add(doubleEntry4);
-                                multiEntryBlockList.add(doubleEntry5);
-
-                                multiEntryFinalBlockList.add(doubleEntryFinal);
-
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry1);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry2);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry3);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry4);
-                                //Log.i("BlockLists", "Multi entry ^ block list added: " + firstEntry + " , " + secondEntry5);
-
-                                //Log.i("BlockLists", "Multi entry final block list added: " + firstEntry + " , " + secondEntryBase);
-                            } else {
-                                String[] doubleEntry = {firstEntry, secondEntry};
-
-                                multiEntryBlockList.add(doubleEntry);
-
-                                //Log.i("BlockLists", "Multi entry block list added: " + firstEntry + " , " + secondEntry);
-                            }
-                        }
-                    } else {
-                        if (blockListEntry.endsWith("^")) {  // `^` matches against `:`, `/`, `?`, `=`, `&`, and the end of the URL.
-                            // Add all the variations to the main block list.
-                            mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + ":");
-                            mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + "/");
-                            mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + "?");
-                            mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + "=");
-                            mainBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1) + "&");
-
-                            // Add the base block entry to the final block list.
-                            finalBlockList.add(blockListEntry.substring(0, blockListEntry.length() - 1));
-
-                            //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + ":");
-                            //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + "/");
-                            //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + "?");
-                            //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + "=");
-                            //Log.i("BlockLists", "Main block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1) + "&");
-                            //Log.i("BlockLists", "Final block list added: " + blockListEntry.substring(0, blockListEntry.length() - 1));
-                        } else {  // This is a basic entry.
-                            // Add the modified block list entry to the main block list.
-                            mainBlockList.add(blockListEntry);
-
-                            //Log.i("BlockLists", "Main block list added: " + blockListEntry);
-                        }
-                    }
-                }
-            }
+        // Instantiate the block list helper.
+        BlockListHelper blockListHelper = new BlockListHelper();
 
-            // Close `bufferedReader`.
-            bufferedReader.close();
-        } catch (IOException e) {
-            // The asset exists, so the `IOException` will never be thrown.
-        }
+        // Parse the block lists.
+        ArrayList<List<String[]>> easyList = blockListHelper.parseBlockList(getAssets(), "blocklists/easylist.txt");
+        ArrayList<List<String[]>> easyPrivacy = blockListHelper.parseBlockList(getAssets(), "blocklists/easyprivacy.txt");
+        ArrayList<List<String[]>> fanboyAnnoyance = blockListHelper.parseBlockList(getAssets(), "blocklists/fanboy-annoyance.txt");
+        ArrayList<List<String[]>> fanboySocial = blockListHelper.parseBlockList(getAssets(), "blocklists/fanboy-social.txt");
 
-        Log.i("BlockLists", "Finish populating block lists");
+        // Get the list versions.
+        easyListVersion = easyList.get(0).get(0)[0];
+        easyPrivacyVersion = easyPrivacy.get(0).get(0)[0];
+        fanboyAnnoyanceVersion = fanboyAnnoyance.get(0).get(0)[0];
+        fanboySocialVersion = fanboySocial.get(0).get(0)[0];
 
         // Set the content view.
         setContentView(R.layout.main_drawerlayout);
@@ -1316,7 +593,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
 
                             /* SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
                              * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
-                             * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically rehides them after they are shown.
+                             * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
                              */
                             rootCoordinatorLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
 
@@ -1594,164 +871,40 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
             @SuppressWarnings("deprecation")
             @Override
             public WebResourceResponse shouldInterceptRequest(WebView view, String url){
-                if (adBlockerEnabled) {  // Check the block lists.
-                    Log.i("BlockLists", "Begin check for " + url);
-
-                    Uri uri = Uri.parse(url);
-                    String domain = uri.getHost();
-
-                    for (String whiteListEntry : mainWhiteList) {
-                        if (url.contains(whiteListEntry)) {
-                            Log.i("BlockLists", "Request allowed by main white list: " + whiteListEntry + " | " + url);
-
-                            // `Return null` loads the requested resource.
-                            return null;
-                        }
+                // Create an empty web resource response to be used if the resource request is blocked.
+                WebResourceResponse emptyWebResourceResponse = new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
+
+                // Check EasyList if it is enabled.
+                if (easyListEnabled) {
+                    if (blockListHelper.isBlocked(formattedUrlString, url, easyList)) {
+                        // The resource request was blocked.  Return an empty web resource response.
+                        return emptyWebResourceResponse;
                     }
+                }
 
-                    for (String[] whiteListEntry : multiEntryWhiteList) {
-                        if (whiteListEntry.length == 2) {  // There are two entries.
-                            if (url.contains(whiteListEntry[0]) && url.contains(whiteListEntry[1])) {
-                                Log.i("BlockLists", "Request allowed by multi entry white list:  " + whiteListEntry[0] + " , " + whiteListEntry[1] + " | " + url);
-
-                                // `Return null` loads the requested resource.
-                                return null;
-                            }
-                        } else {  // There are three entries.
-                            if (url.contains(whiteListEntry[0]) && url.contains(whiteListEntry[1]) && url.contains(whiteListEntry[2])) {
-                                Log.i("BlockLists", "Request allowed by multi entry white list:  " + whiteListEntry[0] + " , " + whiteListEntry[1] + " , " + whiteListEntry[2] + " | " + url);
-
-                                // `Return null` loads the requested resource.
-                                return null;
-                            }
-                        }
-                    }
-
-                    for (String blockListEntry : mainBlockList) {
-                        if (url.contains(blockListEntry)) {
-                            Log.i("BlockLists", "Request blocked by main block list: " + blockListEntry + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
-                    }
-
-                    for (String blockListEntry : initialBlockList) {
-                        if (url.startsWith(blockListEntry)) {
-                            Log.i("BlockLists", "Request blocked by initial block list: " + blockListEntry + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
-                    }
-
-                    for (String blockListEntry : finalBlockList) {
-                        if (url.endsWith(blockListEntry)) {
-                            Log.i("BlockLists", "Request blocked by final block list: " + blockListEntry + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
-                    }
-
-                    for (String[] blockListEntry : multiEntryBlockList) {
-                        if (blockListEntry.length == 2) {  // There are two entries.
-                            if (url.contains(blockListEntry[0]) && url.contains(blockListEntry[1])) {
-                                Log.i("BlockLists", "Request blocked by multi entry block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url);
-
-                                // Return an empty `WebResourceResponse`.
-                                return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                            }
-                        } else {  // There are three entries.
-                            if (url.contains(blockListEntry[0]) && url.contains(blockListEntry[1]) && url.contains(blockListEntry[2])) {
-                                Log.i("BlockLists", "Request blocked by multi entry block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " , " + blockListEntry[2] + " | " + url);
-
-                                // Return an empty `WebResourceResponse`.
-                                return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                            }
-                        }
-                    }
-
-                    for (String[] blockListEntry : multiEntryInitialBlockList) {
-                        if (url.startsWith(blockListEntry[0]) && url.contains(blockListEntry[1])) {
-                            Log.i("BlockLists", "Request blocked by multi entry initial block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
-                    }
-
-                    for (String[] blockListEntry : multiEntryFinalBlockList) {
-                        if (url.contains(blockListEntry[0]) && url.endsWith(blockListEntry[1])) {
-                            Log.i("BlockLists", "Request blocked by multi entry final block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
-                    }
-
-                    for (String[] blockListEntry : domainBlockList) {
-                        if (domain.endsWith(blockListEntry[0]) && url.contains(blockListEntry[1])) {
-                            Log.i("BlockLists", "Request blocked by domain block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
-                    }
-
-                    for (String[] blockListEntry : domainInitialBlockList) {
-                        if (domain.endsWith(blockListEntry[0]) && url.startsWith(blockListEntry[1])) {
-                            Log.i("BlockLists", "Request blocked by domain initial block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
-                    }
-
-                    for (String[] blockListEntry : domainFinalBlockList) {
-                        if (domain.endsWith(blockListEntry[0]) && url.endsWith(blockListEntry[2])) {
-                            Log.i("BlockLists", "Request blocked by domain final block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
-                    }
-
-                    for (String[] blockListEntry : domainMultiEntryBlockList) {
-                        if (domain.endsWith(blockListEntry[0]) && url.contains(blockListEntry[1]) && url.contains(blockListEntry[2])) {
-                            Log.i("BlockLists", "Request blocked by domain multi entry block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " , " + blockListEntry[2] + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
+                // Check EasyPrivacy if it is enabled.
+                if (easyPrivacyEnabled) {
+                    if (blockListHelper.isBlocked(formattedUrlString, url, easyPrivacy)) {
+                        // The resource request was blocked.  Return an empty web resource response.
+                        return emptyWebResourceResponse;
                     }
+                }
 
-                    for (String[] blockListEntry : domainRegularExpressionBlockList) {
-                        if (domain.endsWith(blockListEntry[0]) && Pattern.matches(blockListEntry[1], url)) {
-                            Log.i("BlockLists", "Request blocked by domain regular expression block list: " + blockListEntry[0] + " , " + blockListEntry[1] + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
+                // Check Fanboy’s Annoyance List if it is enabled.
+                if (fanboyAnnoyanceListEnabled) {
+                    if (blockListHelper.isBlocked(formattedUrlString, url, fanboyAnnoyance)) {
+                        // The resource request was blocked.  Return an empty web resource response.
+                        return emptyWebResourceResponse;
                     }
-
-                    for (String blockListEntry : regularExpressionBlockList) {
-                        if (Pattern.matches(blockListEntry, url)) {
-                            Log.i("BlockLists", "Request blocked by regular expression block list: " + blockListEntry + " | " + url);
-
-                            // Return an empty `WebResourceResponse`.
-                            return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
-                        }
+                } else if (fanboySocialBlockingListEnabled){  // Only check Fanboy’s Social Blocking List if Fanboy’s Annoyance List is disabled.
+                    if (blockListHelper.isBlocked(formattedUrlString, url, fanboySocial)) {
+                        // The resource request was blocked.  Return an empty web resource response.
+                        return emptyWebResourceResponse;
                     }
-
-                    Log.i("BlockLists", "End check for " + url);
-
-                    // `return null` loads the requested resource.
-                    return null;
-                } else {  // Ad blocking is disabled.
-                    // `return null` loads the requested resource.
-                    return null;
                 }
+
+                // The resource request has not been blocked.  `return null` loads the requested resource.
+                return null;
             }
 
             // Handle HTTP authentication requests.
@@ -2046,7 +1199,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
 
                 /* SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
                  * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
-                 * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically rehides them after they are shown.
+                 * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
                  */
                 rootCoordinatorLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
 
@@ -3656,6 +2809,9 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
             formattedUrlString = searchURL + encodedUrlString;
         }
 
+        // Clear the focus from the URL text box.  Otherwise, proximate typing in the box will retain the colorized formatting instead of being reset during refocus.
+        urlTextBox.clearFocus();
+
         loadUrl(formattedUrlString);
     }
 
@@ -3709,7 +2865,10 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
         String torSearchCustomURLString = sharedPreferences.getString("tor_search_custom_url", "");
         String searchString = sharedPreferences.getString("search", "https://duckduckgo.com/html/?q=");
         String searchCustomURLString = sharedPreferences.getString("search_custom_url", "");
-        adBlockerEnabled = sharedPreferences.getBoolean("block_ads", true);
+        easyListEnabled = sharedPreferences.getBoolean("easylist", true);
+        easyPrivacyEnabled = sharedPreferences.getBoolean("easyprivacy", true);
+        fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboy_annoyance_list", true);
+        fanboySocialBlockingListEnabled = sharedPreferences.getBoolean("fanboy_social_blocking_list", true);
         incognitoModeEnabled = sharedPreferences.getBoolean("incognito_mode", false);
         boolean doNotTrackEnabled = sharedPreferences.getBoolean("do_not_track", false);
         boolean proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
@@ -3808,7 +2967,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
 
                 /* SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
                  * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
-                 * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically rehides them after they are shown.
+                 * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
                  */
                 rootCoordinatorLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
             } else {  // Hide everything except the status and navigation bars.