X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Factivities%2FMainWebViewActivity.java;h=c4715ec5a0fb4ae144dcf1c0c6a5f24e86956f32;hp=cfe93f2740163d27a76435965151891ecfe69404;hb=6849b42dea845a29d5cfbc709b25b134846754e9;hpb=f85107c894bdb2311c0ba86313daaa0378c0bb16 diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index cfe93f27..c4715ec5 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -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; @@ -300,6 +301,9 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // `reapplyDomainSettingsOnRestart` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, and `onAddDomain()`, . private boolean reapplyDomainSettingsOnRestart; + // `reapplyAppSettingsOnRestart` is used in `onNavigationItemSelected()` and `onRestart()`. + private boolean reapplyAppSettingsOnRestert; + // `currentDomainName` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onAddDomain()`, and `applyDomainSettings()`. private String currentDomainName; @@ -408,745 +412,6 @@ 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 mainWhiteList = new LinkedList<>(); - List multiEntryWhiteList = new LinkedList<>(); - List mainBlockList = new LinkedList<>(); - List initialBlockList = new LinkedList<>(); - List finalBlockList = new LinkedList<>(); - List multiEntryBlockList = new LinkedList<>(); - List multiEntryInitialBlockList = new LinkedList<>(); - List multiEntryFinalBlockList = new LinkedList<>(); - List domainBlockList = new LinkedList<>(); - List domainInitialBlockList = new LinkedList<>(); - List domainFinalBlockList = new LinkedList<>(); - List domainMultiEntryBlockList = new LinkedList<>(); - List domainRegularExpressionBlockList = new LinkedList<>(); - List 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); - } - } - } - } - - // Close `bufferedReader`. - bufferedReader.close(); - } catch (IOException e) { - // The asset exists, so the `IOException` will never be thrown. - } - - Log.i("BlockLists", "Finish populating block lists"); - // Set the content view. setContentView(R.layout.main_drawerlayout); @@ -1316,7 +581,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); @@ -1545,6 +810,230 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // drawerToggle creates the hamburger icon at the start of the AppBar. drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, supportAppBar, R.string.open_navigation_drawer, R.string.close_navigation_drawer); + // Get a handle for the progress bar. + final ProgressBar progressBar = findViewById(R.id.progress_bar); + + mainWebView.setWebChromeClient(new WebChromeClient() { + // Update the progress bar when a page is loading. + @Override + public void onProgressChanged(WebView view, int progress) { + // Inject the night mode CSS if night mode is enabled. + if (nightMode) { + // `background-color: #212121` sets the background to be dark gray. `color: #BDBDBD` sets the text color to be light gray. `box-shadow: none` removes a lower underline on links + // used by WordPress. `text-decoration: none` removes all text underlines. `text-shadow: none` removes text shadows, which usually have a hard coded color. + // `border: none` removes all borders, which can also be used to underline text. + // `a {color: #1565C0}` sets links to be a dark blue. `!important` takes precedent over any existing sub-settings. + mainWebView.evaluateJavascript("(function() {var parent = document.getElementsByTagName('head').item(0); var style = document.createElement('style'); style.type = 'text/css'; " + + "style.innerHTML = '* {background-color: #212121 !important; color: #BDBDBD !important; box-shadow: none !important; text-decoration: none !important;" + + "text-shadow: none !important; border: none !important;} a {color: #1565C0 !important;}'; parent.appendChild(style)})()", value -> { + // Initialize a `Handler` to display `mainWebView`. + Handler displayWebViewHandler = new Handler(); + + // Setup a `Runnable` to display `mainWebView` after a delay to allow the CSS to be applied. + Runnable displayWebViewRunnable = () -> { + // Only display `mainWebView` if the progress bar is one. This prevents the display of the `WebView` while it is still loading. + if (progressBar.getVisibility() == View.GONE) { + mainWebView.setVisibility(View.VISIBLE); + } + }; + + // Use `displayWebViewHandler` to delay the displaying of `mainWebView` for 500 milliseconds. + displayWebViewHandler.postDelayed(displayWebViewRunnable, 500); + }); + } + + // Update the progress bar. + progressBar.setProgress(progress); + + // Set the visibility of the progress bar. + if (progress < 100) { + // Show the progress bar. + progressBar.setVisibility(View.VISIBLE); + } else { + // Hide the progress bar. + progressBar.setVisibility(View.GONE); + + // Display `mainWebView` if night mode is disabled. + // Because of a race condition between `applyDomainSettings` and `onPageStarted`, when night mode is set by domain settings the `WebView` may be hidden even if night mode is not + // currently enabled. + if (!nightMode) { + mainWebView.setVisibility(View.VISIBLE); + } + + //Stop the `SwipeToRefresh` indicator if it is running + swipeRefreshLayout.setRefreshing(false); + } + } + + // Set the favorite icon when it changes. + @Override + public void onReceivedIcon(WebView view, Bitmap icon) { + // Only update the favorite icon if the website has finished loading. + if (progressBar.getVisibility() == View.GONE) { + // Save a copy of the favorite icon. + favoriteIconBitmap = icon; + + // Place the favorite icon in the appBar. + favoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true)); + } + } + + // Save a copy of the title when it changes. + @Override + public void onReceivedTitle(WebView view, String title) { + // Save a copy of the title. + webViewTitle = title; + } + + // Enter full screen video + @Override + public void onShowCustomView(View view, CustomViewCallback callback) { + // Pause the ad if this is the free flavor. + if (BuildConfig.FLAVOR.contentEquals("free")) { + BannerAd.pauseAd(adView); + } + + // Remove the translucent overlays. + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + + // Remove the translucent status bar overlay on the `Drawer Layout`, which is special and needs its own command. + drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + + /* 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 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); + + // Set `rootCoordinatorLayout` to fill the entire screen. + rootCoordinatorLayout.setFitsSystemWindows(false); + + // Add `view` to `fullScreenVideoFrameLayout` and display it on the screen. + fullScreenVideoFrameLayout.addView(view); + fullScreenVideoFrameLayout.setVisibility(View.VISIBLE); + } + + // Exit full screen video + public void onHideCustomView() { + // Hide `fullScreenVideoFrameLayout`. + fullScreenVideoFrameLayout.removeAllViews(); + fullScreenVideoFrameLayout.setVisibility(View.GONE); + + // Add the translucent status flag. This also resets `drawerLayout's` `View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN`. + getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + + // Set `rootCoordinatorLayout` to fit inside the status and navigation bars. This also clears the `SYSTEM_UI` flags. + rootCoordinatorLayout.setFitsSystemWindows(true); + + // Show the ad if this is the free flavor. + if (BuildConfig.FLAVOR.contentEquals("free")) { + // Reload the ad. Because the screen may have rotated, we need to use `reloadAfterRotate`. + BannerAd.reloadAfterRotate(adView, getApplicationContext(), getString(R.string.ad_id)); + + // Reinitialize the `adView` variable, as the `View` will have been removed and re-added by `BannerAd.reloadAfterRotate()`. + adView = findViewById(R.id.adview); + } + } + }); + + // Register `mainWebView` for a context menu. This is used to see link targets and download images. + registerForContextMenu(mainWebView); + + // Allow the downloading of files. + mainWebView.setDownloadListener((String url, String userAgent, String contentDisposition, String mimetype, long contentLength) -> { + // Show the `DownloadFileDialog` `AlertDialog` and name this instance `@string/download`. + AppCompatDialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(url, contentDisposition, contentLength); + downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download)); + }); + + // Allow pinch to zoom. + mainWebView.getSettings().setBuiltInZoomControls(true); + + // Hide zoom controls. + mainWebView.getSettings().setDisplayZoomControls(false); + + // Set `mainWebView` to use a wide viewport. Otherwise, some web pages will be scrunched and some content will render outside the screen. + mainWebView.getSettings().setUseWideViewPort(true); + + // Set `mainWebView` to load in overview mode (zoomed out to the maximum width). + mainWebView.getSettings().setLoadWithOverviewMode(true); + + // Explicitly disable geolocation. + mainWebView.getSettings().setGeolocationEnabled(false); + + // Initialize cookieManager. + cookieManager = CookieManager.getInstance(); + + // Replace the header that `WebView` creates for `X-Requested-With` with a null value. The default value is the application ID (com.stoutner.privacybrowser.standard). + customHeaders.put("X-Requested-With", ""); + + // Initialize the default preference values the first time the program is run. `this` is the context. `false` keeps this command from resetting any current preferences back to default. + PreferenceManager.setDefaultValues(this, R.xml.preferences, false); + + // Get the intent that started the app. + final Intent launchingIntent = getIntent(); + + // Extract the launching intent data as `launchingIntentUriData`. + final Uri launchingIntentUriData = launchingIntent.getData(); + + // Convert the launching intent URI data (if it exists) to a string and store it in `formattedUrlString`. + if (launchingIntentUriData != null) { + formattedUrlString = launchingIntentUriData.toString(); + } + + // Get a handle for the `Runtime`. + privacyBrowserRuntime = Runtime.getRuntime(); + + // Store the application's private data directory. + privateDataDirectoryString = getApplicationInfo().dataDir; + // `dataDir` will vary, but will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`. + + // Initialize `inFullScreenBrowsingMode`, which is always false at this point because Privacy Browser never starts in full screen browsing mode. + inFullScreenBrowsingMode = false; + + // Initialize AdView for the free flavor. + adView = findViewById(R.id.adview); + + // Initialize the privacy settings variables. + javaScriptEnabled = false; + firstPartyCookiesEnabled = false; + thirdPartyCookiesEnabled = false; + domStorageEnabled = false; + saveFormDataEnabled = false; + nightMode = false; + + // Initialize `webViewTitle`. + webViewTitle = getString(R.string.no_title); + + // Initialize `favoriteIconBitmap`. `ContextCompat` must be used until API >= 21. + Drawable favoriteIconDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.world); + BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable; + assert favoriteIconBitmapDrawable != null; + favoriteIconDefaultBitmap = favoriteIconBitmapDrawable.getBitmap(); + + // If the favorite icon is null, load the default. + if (favoriteIconBitmap == null) { + favoriteIconBitmap = favoriteIconDefaultBitmap; + } + + // Apply the app settings from the shared preferences. + applyAppSettings(); + + // Instantiate the block list helper. + BlockListHelper blockListHelper = new BlockListHelper(); + + // Parse the block lists. + final ArrayList> easyList = blockListHelper.parseBlockList(getAssets(), "blocklists/easylist.txt"); + final ArrayList> easyPrivacy = blockListHelper.parseBlockList(getAssets(), "blocklists/easyprivacy.txt"); + final ArrayList> fanboyAnnoyance = blockListHelper.parseBlockList(getAssets(), "blocklists/fanboy-annoyance.txt"); + final ArrayList> fanboySocial = blockListHelper.parseBlockList(getAssets(), "blocklists/fanboy-social.txt"); + + // Store 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]; + mainWebView.setWebViewClient(new WebViewClient() { // `shouldOverrideUrlLoading` makes this `WebView` the default handler for URLs inside the app, so that links are not kicked out to other apps. // We have to use the deprecated `shouldOverrideUrlLoading` until API >= 24. @@ -1583,175 +1072,51 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD return true; } else { // Load the URL in Privacy Browser. // Apply the domain settings for the new URL. - applyDomainSettings(url); + applyDomainSettings(url, true); // Returning `false` causes the current `WebView` to handle the URL and prevents it from adding redirects to the history list. return false; } - } - - // Check requests against the block lists. The deprecated `shouldInterceptRequest` must be used until minimum API >= 21. - @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; - } - } - - 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())); - } + // Check requests against the block lists. The deprecated `shouldInterceptRequest` must be used until minimum API >= 21. + @SuppressWarnings("deprecation") + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, String url){ + // 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[] 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. @@ -1767,8 +1132,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Update the URL in urlTextBox when the page starts to load. @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - // If night mode is enabled, hide `mainWebView` until after the night mode CSS is applied. + public void onPageStarted(WebView view, String url, Bitmap favicon) {// If night mode is enabled, hide `mainWebView` until after the night mode CSS is applied. if (nightMode) { mainWebView.setVisibility(View.INVISIBLE); } @@ -1789,7 +1153,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Apply any custom domain settings if the URL was loaded by navigating history. if (navigatingHistory) { - applyDomainSettings(url); + applyDomainSettings(url, true); } // Set `urlIsLoading` to `true`, so that redirects while loading do not trigger changes in the user agent, which forces another reload of the existing page. @@ -1800,6 +1164,11 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // It is necessary to update `formattedUrlString` and `urlTextBox` after the page finishes loading because the final URL can change during load. @Override public void onPageFinished(WebView view, String url) { + // Flush any cookies to persistent storage. `CookieManager` has become very lazy about flushing cookies in recent versions. + if (firstPartyCookiesEnabled && Build.VERSION.SDK_INT >= 21) { + cookieManager.flush(); + } + // Reset `urlIsLoading`, which is used to prevent reloads on redirect if the user agent changes. urlIsLoading = false; @@ -1839,7 +1208,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD inputMethodManager.showSoftInput(urlTextBox, 0); // Apply the domain settings. This clears any settings from the previous domain. - applyDomainSettings(formattedUrlString); + applyDomainSettings(formattedUrlString, true); } else { // `WebView` has loaded a webpage. // Set `formattedUrlString`. formattedUrlString = url; @@ -1910,7 +1279,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD !currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) || !currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) || !currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) || !currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) || !currentWebsiteSslStartDateString.equals(pinnedDomainSslStartDateString) || !currentWebsiteSslEndDateString.equals(pinnedDomainSslEndDateString)) { - // The pinned SSL certificate doesn't match the current domain certificate. + // The pinned SSL certificate doesn't match the current domain certificate. //Display the pinned SSL certificate mismatch `AlertDialog`. AppCompatDialogFragment pinnedSslCertificateMismatchDialogFragment = new PinnedSslCertificateMismatchDialog(); pinnedSslCertificateMismatchDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_mismatch)); @@ -1941,7 +1310,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) && currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) && currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) && currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) && currentWebsiteSslStartDate.equals(pinnedDomainSslStartDate) && currentWebsiteSslEndDate.equals(pinnedDomainSslEndDate)) { - // An SSL certificate is pinned and matches the current domain certificate. + // An SSL certificate is pinned and matches the current domain certificate. // Proceed to the website without displaying an error. handler.proceed(); } else { // Either there isn't a pinned SSL certificate or it doesn't match the current website certificate. @@ -1955,216 +1324,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD } }); - // Get a handle for the progress bar. - final ProgressBar progressBar = findViewById(R.id.progress_bar); - - mainWebView.setWebChromeClient(new WebChromeClient() { - // Update the progress bar when a page is loading. - @Override - public void onProgressChanged(WebView view, int progress) { - // Inject the night mode CSS if night mode is enabled. - if (nightMode) { - // `background-color: #212121` sets the background to be dark gray. `color: #BDBDBD` sets the text color to be light gray. `box-shadow: none` removes a lower underline on links - // used by WordPress. `text-decoration: none` removes all text underlines. `text-shadow: none` removes text shadows, which usually have a hard coded color. - // `border: none` removes all borders, which can also be used to underline text. - // `a {color: #1565C0}` sets links to be a dark blue. `!important` takes precedent over any existing sub-settings. - mainWebView.evaluateJavascript("(function() {var parent = document.getElementsByTagName('head').item(0); var style = document.createElement('style'); style.type = 'text/css'; " + - "style.innerHTML = '* {background-color: #212121 !important; color: #BDBDBD !important; box-shadow: none !important; text-decoration: none !important;" + - "text-shadow: none !important; border: none !important;} a {color: #1565C0 !important;}'; parent.appendChild(style)})()", value -> { - // Initialize a `Handler` to display `mainWebView`. - Handler displayWebViewHandler = new Handler(); - - // Setup a `Runnable` to display `mainWebView` after a delay to allow the CSS to be applied. - Runnable displayWebViewRunnable = () -> { - // Only display `mainWebView` if the progress bar is one. This prevents the display of the `WebView` while it is still loading. - if (progressBar.getVisibility() == View.GONE) { - mainWebView.setVisibility(View.VISIBLE); - } - }; - - // Use `displayWebViewHandler` to delay the displaying of `mainWebView` for 500 milliseconds. - displayWebViewHandler.postDelayed(displayWebViewRunnable, 500); - }); - } - - // Update the progress bar. - progressBar.setProgress(progress); - - // Set the visibility of the progress bar. - if (progress < 100) { - // Show the progress bar. - progressBar.setVisibility(View.VISIBLE); - } else { - // Hide the progress bar. - progressBar.setVisibility(View.GONE); - - // Display `mainWebView` if night mode is disabled. - // Because of a race condition between `applyDomainSettings` and `onPageStarted`, when night mode is set by domain settings the `WebView` may be hidden even if night mode is not - // currently enabled. - if (!nightMode) { - mainWebView.setVisibility(View.VISIBLE); - } - - //Stop the `SwipeToRefresh` indicator if it is running - swipeRefreshLayout.setRefreshing(false); - } - } - - // Set the favorite icon when it changes. - @Override - public void onReceivedIcon(WebView view, Bitmap icon) { - // Only update the favorite icon if the website has finished loading. - if (progressBar.getVisibility() == View.GONE) { - // Save a copy of the favorite icon. - favoriteIconBitmap = icon; - - // Place the favorite icon in the appBar. - favoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true)); - } - } - - // Save a copy of the title when it changes. - @Override - public void onReceivedTitle(WebView view, String title) { - // Save a copy of the title. - webViewTitle = title; - } - - // Enter full screen video - @Override - public void onShowCustomView(View view, CustomViewCallback callback) { - // Pause the ad if this is the free flavor. - if (BuildConfig.FLAVOR.contentEquals("free")) { - BannerAd.pauseAd(adView); - } - - // Remove the translucent overlays. - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - - // Remove the translucent status bar overlay on the `Drawer Layout`, which is special and needs its own command. - drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - - /* 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. - */ - rootCoordinatorLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - - // Set `rootCoordinatorLayout` to fill the entire screen. - rootCoordinatorLayout.setFitsSystemWindows(false); - - // Add `view` to `fullScreenVideoFrameLayout` and display it on the screen. - fullScreenVideoFrameLayout.addView(view); - fullScreenVideoFrameLayout.setVisibility(View.VISIBLE); - } - - // Exit full screen video - public void onHideCustomView() { - // Hide `fullScreenVideoFrameLayout`. - fullScreenVideoFrameLayout.removeAllViews(); - fullScreenVideoFrameLayout.setVisibility(View.GONE); - - // Add the translucent status flag. This also resets `drawerLayout's` `View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN`. - getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - - // Set `rootCoordinatorLayout` to fit inside the status and navigation bars. This also clears the `SYSTEM_UI` flags. - rootCoordinatorLayout.setFitsSystemWindows(true); - - // Show the ad if this is the free flavor. - if (BuildConfig.FLAVOR.contentEquals("free")) { - // Reload the ad. Because the screen may have rotated, we need to use `reloadAfterRotate`. - BannerAd.reloadAfterRotate(adView, getApplicationContext(), getString(R.string.ad_id)); - - // Reinitialize the `adView` variable, as the `View` will have been removed and re-added by `BannerAd.reloadAfterRotate()`. - adView = findViewById(R.id.adview); - } - } - }); - - // Register `mainWebView` for a context menu. This is used to see link targets and download images. - registerForContextMenu(mainWebView); - - // Allow the downloading of files. - mainWebView.setDownloadListener((String url, String userAgent, String contentDisposition, String mimetype, long contentLength) -> { - // Show the `DownloadFileDialog` `AlertDialog` and name this instance `@string/download`. - AppCompatDialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(url, contentDisposition, contentLength); - downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download)); - }); - - // Allow pinch to zoom. - mainWebView.getSettings().setBuiltInZoomControls(true); - - // Hide zoom controls. - mainWebView.getSettings().setDisplayZoomControls(false); - - // Set `mainWebView` to use a wide viewport. Otherwise, some web pages will be scrunched and some content will render outside the screen. - mainWebView.getSettings().setUseWideViewPort(true); - - // Set `mainWebView` to load in overview mode (zoomed out to the maximum width). - mainWebView.getSettings().setLoadWithOverviewMode(true); - - // Explicitly disable geolocation. - mainWebView.getSettings().setGeolocationEnabled(false); - - // Initialize cookieManager. - cookieManager = CookieManager.getInstance(); - - // Replace the header that `WebView` creates for `X-Requested-With` with a null value. The default value is the application ID (com.stoutner.privacybrowser.standard). - customHeaders.put("X-Requested-With", ""); - - // Initialize the default preference values the first time the program is run. `this` is the context. `false` keeps this command from resetting any current preferences back to default. - PreferenceManager.setDefaultValues(this, R.xml.preferences, false); - - // Get the intent that started the app. - final Intent launchingIntent = getIntent(); - - // Extract the launching intent data as `launchingIntentUriData`. - final Uri launchingIntentUriData = launchingIntent.getData(); - - // Convert the launching intent URI data (if it exists) to a string and store it in `formattedUrlString`. - if (launchingIntentUriData != null) { - formattedUrlString = launchingIntentUriData.toString(); - } - - // Get a handle for the `Runtime`. - privacyBrowserRuntime = Runtime.getRuntime(); - - // Store the application's private data directory. - privateDataDirectoryString = getApplicationInfo().dataDir; - // `dataDir` will vary, but will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`. - - // Initialize `inFullScreenBrowsingMode`, which is always false at this point because Privacy Browser never starts in full screen browsing mode. - inFullScreenBrowsingMode = false; - - // Initialize AdView for the free flavor. - adView = findViewById(R.id.adview); - - // Initialize the privacy settings variables. - javaScriptEnabled = false; - firstPartyCookiesEnabled = false; - thirdPartyCookiesEnabled = false; - domStorageEnabled = false; - saveFormDataEnabled = false; - nightMode = false; - - // Initialize `webViewTitle`. - webViewTitle = getString(R.string.no_title); - - // Initialize `favoriteIconBitmap`. `ContextCompat` must be used until API >= 21. - Drawable favoriteIconDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.world); - BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable; - assert favoriteIconBitmapDrawable != null; - favoriteIconDefaultBitmap = favoriteIconBitmapDrawable.getBitmap(); - - // If the favorite icon is null, load the default. - if (favoriteIconBitmap == null) { - favoriteIconBitmap = favoriteIconDefaultBitmap; - } - - // Apply the app settings from the shared preferences. - applyAppSettings(); - - // Load `formattedUrlString` if we are not waiting for Orbot to connect. + // Load the website if not waiting for Orbot to connect. if (!waitingForOrbot) { loadUrl(formattedUrlString); } @@ -2175,22 +1335,23 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Sets the new intent as the activity intent, so that any future `getIntent()`s pick up this one instead of creating a new activity. setIntent(intent); + // Check to see if the intent contains a new URL. if (intent.getData() != null) { // Get the intent data and convert it to a string. final Uri intentUriData = intent.getData(); formattedUrlString = intentUriData.toString(); - } - // Close the navigation drawer if it is open. - if (drawerLayout.isDrawerVisible(GravityCompat.START)) { - drawerLayout.closeDrawer(GravityCompat.START); - } + // Load the website. + loadUrl(formattedUrlString); - // Load the website. - loadUrl(formattedUrlString); + // Close the navigation drawer if it is open. + if (drawerLayout.isDrawerVisible(GravityCompat.START)) { + drawerLayout.closeDrawer(GravityCompat.START); + } - // Clear the keyboard if displayed and remove the focus on the urlTextBar if it has it. - mainWebView.requestFocus(); + // Clear the keyboard if displayed and remove the focus on the urlTextBar if it has it. + mainWebView.requestFocus(); + } } @Override @@ -2198,31 +1359,31 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Run the default commands. super.onRestart(); - // Apply the app settings, which may have been changed in `SettingsActivity`. - applyAppSettings(); - - // Apply the domain settings if returning from the Domains Activity. - if (reapplyDomainSettingsOnRestart) { - // Reset `reapplyDomainSettingsOnRestart`. - reapplyDomainSettingsOnRestart = false; + // Apply the app settings if returning from the Settings activity.. + if (reapplyAppSettingsOnRestert) { + // Apply the app settings. + applyAppSettings(); - // Reapply the domain settings. - applyDomainSettings(formattedUrlString); - } + // Reload the webpage if displaying of images has been disabled in the Settings activity. + if (reloadOnRestart) { + // Reload `mainWebView`. + mainWebView.reload(); - // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step. - updatePrivacyIcons(true); + // Reset `reloadOnRestartBoolean`. + reloadOnRestart = false; + } - // Set the display webpage images mode. - setDisplayWebpageImages(); + // Reset the return from settings flag. + reapplyAppSettingsOnRestert = false; + } - // Reload the webpage if displaying of images has been disabled in `SettingsFragment`. - if (reloadOnRestart) { - // Reload `mainWebView`. - mainWebView.reload(); + // Apply the domain settings if returning from the Domains activity. + if (reapplyDomainSettingsOnRestart) { + // Reapply the domain settings. + applyDomainSettings(formattedUrlString, false); - // Reset `reloadOnRestartBoolean`. - reloadOnRestart = false; + // Reset `reapplyDomainSettingsOnRestart`. + reapplyDomainSettingsOnRestart = false; } // Load the URL on restart to apply changes to night mode. @@ -2234,7 +1395,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD loadUrlOnRestart = false; } - // + // Update the bookmarks drawer if returning from the Bookmarks activity. if (restartFromBookmarksActivity) { // Close the bookmarks drawer. drawerLayout.closeDrawer(GravityCompat.END); @@ -2245,6 +1406,9 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Reset `restartFromBookmarksActivity`. restartFromBookmarksActivity = false; } + + // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step. This can be important if the screen was rotated. + updatePrivacyIcons(true); } // `onResume()` runs after `onStart()`, which runs after `onCreate()` and `onRestart()`. @@ -2858,7 +2022,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD break; case R.id.domains: - // Reapply the domain settings on returning to `MainWebViewActivity`. + // Set the flag to reapply the domain settings on restart when returning from Domain Settings. reapplyDomainSettingsOnRestart = true; currentDomainName = ""; @@ -2868,7 +2032,10 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD break; case R.id.settings: - // Reapply the domain settings on returning to `MainWebViewActivity`. + // Set the flag to reapply app settings on restart when returning from Settings. + reapplyAppSettingsOnRestert = true; + + // Set the flag to reapply the domain settings on restart when returning from Settings. reapplyDomainSettingsOnRestart = true; currentDomainName = ""; @@ -3656,13 +2823,16 @@ 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); } private void loadUrl(String url) { // Apply any custom domain settings. - applyDomainSettings(url); + applyDomainSettings(url, true); // Load the URL. mainWebView.loadUrl(url, customHeaders); @@ -3709,7 +2879,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 +2981,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. @@ -3855,9 +3028,10 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD } } - // We have to use the deprecated `.getDrawable()` until the minimum API >= 21. + // + // The deprecated `.getDrawable()` must be used until the minimum API >= 21. @SuppressWarnings("deprecation") - private void applyDomainSettings(String url) { + private void applyDomainSettings(String url, boolean resetFavoriteIcon) { // Reset `navigatingHistory`. navigatingHistory = false; @@ -3879,7 +3053,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD loadingNewDomainName = !hostName.equals(currentDomainName); } - // Only apply the domain settings if we are loading a new domain. This allows the user to set temporary settings for JavaScript, cookies, DOM storage, etc. + // Only apply the domain settings if a new domain is being loaded. This allows the user to set temporary settings for JavaScript, cookies, DOM storage, etc. if (loadingNewDomainName) { // Set the new `hostname` as the `currentDomainName`. currentDomainName = hostName; @@ -3887,9 +3061,11 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD // Reset `ignorePinnedSslCertificate`. ignorePinnedSslCertificate = false; - // Reset `favoriteIconBitmap` and display it in the `appbar`. - favoriteIconBitmap = favoriteIconDefaultBitmap; - favoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(favoriteIconBitmap, 64, 64, true)); + // Reset the favorite icon if specified. + if (resetFavoriteIcon) { + favoriteIconBitmap = favoriteIconDefaultBitmap; + favoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(favoriteIconBitmap, 64, 64, true)); + } // Initialize the database handler. `this` specifies the context. The two `nulls` do not specify the database name or a `CursorFactory`. // The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.