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;
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;
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;
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,
// `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;
// `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()`.
// `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;
// 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);
- }
- }
- }
- }
-
- // 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);
/* 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);
// 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);
- 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.
- @SuppressWarnings("deprecation")
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- if (url.startsWith("mailto:")) { // Load the email address in an external email program.
- // Use `ACTION_SENDTO` instead of `ACTION_SEND` so that only email programs are launched.
- Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
+ // Get a handle for the progress bar.
+ final ProgressBar progressBar = findViewById(R.id.progress_bar);
- // Parse the url and set it as the data for the `Intent`.
- emailIntent.setData(Uri.parse(url));
+ 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();
- // `FLAG_ACTIVITY_NEW_TASK` opens the email program in a new task instead as part of Privacy Browser.
- emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // 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);
+ }
+ };
- // Make it so.
- startActivity(emailIntent);
+ // Use `displayWebViewHandler` to delay the displaying of `mainWebView` for 500 milliseconds.
+ displayWebViewHandler.postDelayed(displayWebViewRunnable, 500);
+ });
+ }
- // Returning `true` indicates the application is handling the URL.
- return true;
- } else if (url.startsWith("tel:")) { // Load the phone number in the dialer.
- // `ACTION_DIAL` open the dialer and loads the phone number, but waits for the user to place the call.
- Intent dialIntent = new Intent(Intent.ACTION_DIAL);
+ // Update the progress bar.
+ progressBar.setProgress(progress);
- // Add the phone number to the intent.
- dialIntent.setData(Uri.parse(url));
+ // 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);
- // `FLAG_ACTIVITY_NEW_TASK` opens the dialer in a new task instead as part of Privacy Browser.
- dialIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // 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);
+ }
- // Make it so.
- startActivity(dialIntent);
+ //Stop the `SwipeToRefresh` indicator if it is running
+ swipeRefreshLayout.setRefreshing(false);
+ }
+ }
- // Returning `true` indicates the application is handling the URL.
- return true;
- } else { // Load the URL in Privacy Browser.
- // Apply the domain settings for the new URL.
- applyDomainSettings(url);
+ // 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;
- // Returning `false` causes the current `WebView` to handle the URL and prevents it from adding redirects to the history list.
- return false;
+ // Place the favorite icon in the appBar.
+ favoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true));
}
}
- // Check requests against the block lists. The deprecated `shouldInterceptRequest` must be used until minimum API >= 21.
- @SuppressWarnings("deprecation")
+ // Save a copy of the title when it changes.
@Override
- public WebResourceResponse shouldInterceptRequest(WebView view, String url){
- if (adBlockerEnabled) { // Check the block lists.
- Log.i("BlockLists", "Begin check for " + url);
+ public void onReceivedTitle(WebView view, String title) {
+ // Save a copy of the title.
+ webViewTitle = title;
+ }
- Uri uri = Uri.parse(url);
- String domain = uri.getHost();
+ // 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);
+ }
- for (String whiteListEntry : mainWhiteList) {
- if (url.contains(whiteListEntry)) {
- Log.i("BlockLists", "Request allowed by main white list: " + whiteListEntry + " | " + url);
+ // Remove the translucent overlays.
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- // `Return null` loads the requested resource.
- return null;
- }
- }
+ // 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);
- 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);
+ /* 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);
- // `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);
+ // Set `rootCoordinatorLayout` to fill the entire screen.
+ rootCoordinatorLayout.setFitsSystemWindows(false);
- // `Return null` loads the requested resource.
- return null;
- }
- }
- }
+ // Add `view` to `fullScreenVideoFrameLayout` and display it on the screen.
+ fullScreenVideoFrameLayout.addView(view);
+ fullScreenVideoFrameLayout.setVisibility(View.VISIBLE);
+ }
- for (String blockListEntry : mainBlockList) {
- if (url.contains(blockListEntry)) {
- Log.i("BlockLists", "Request blocked by main block list: " + blockListEntry + " | " + url);
+ // Exit full screen video
+ public void onHideCustomView() {
+ // Hide `fullScreenVideoFrameLayout`.
+ fullScreenVideoFrameLayout.removeAllViews();
+ fullScreenVideoFrameLayout.setVisibility(View.GONE);
- // Return an empty `WebResourceResponse`.
- return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
- }
- }
+ // Add the translucent status flag. This also resets `drawerLayout's` `View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN`.
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- for (String blockListEntry : initialBlockList) {
- if (url.startsWith(blockListEntry)) {
- Log.i("BlockLists", "Request blocked by initial block list: " + blockListEntry + " | " + url);
+ // Set `rootCoordinatorLayout` to fit inside the status and navigation bars. This also clears the `SYSTEM_UI` flags.
+ rootCoordinatorLayout.setFitsSystemWindows(true);
- // Return an empty `WebResourceResponse`.
- return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
- }
- }
+ // 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));
- for (String blockListEntry : finalBlockList) {
- if (url.endsWith(blockListEntry)) {
- Log.i("BlockLists", "Request blocked by final block list: " + blockListEntry + " | " + url);
+ // Reinitialize the `adView` variable, as the `View` will have been removed and re-added by `BannerAd.reloadAfterRotate()`.
+ adView = findViewById(R.id.adview);
+ }
+ }
+ });
- // Return an empty `WebResourceResponse`.
- return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
- }
- }
+ // Register `mainWebView` for a context menu. This is used to see link targets and download images.
+ registerForContextMenu(mainWebView);
- 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);
+ // 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));
+ });
- // 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);
+ // Allow pinch to zoom.
+ mainWebView.getSettings().setBuiltInZoomControls(true);
- // Return an empty `WebResourceResponse`.
- return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
- }
- }
- }
+ // Hide zoom controls.
+ mainWebView.getSettings().setDisplayZoomControls(false);
- 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);
+ // 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);
- // Return an empty `WebResourceResponse`.
- return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
- }
- }
+ // Set `mainWebView` to load in overview mode (zoomed out to the maximum width).
+ mainWebView.getSettings().setLoadWithOverviewMode(true);
- 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);
+ // Explicitly disable geolocation.
+ mainWebView.getSettings().setGeolocationEnabled(false);
- // Return an empty `WebResourceResponse`.
- return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
- }
- }
+ // 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<List<String[]>> easyList = blockListHelper.parseBlockList(getAssets(), "blocklists/easylist.txt");
+ final ArrayList<List<String[]>> easyPrivacy = blockListHelper.parseBlockList(getAssets(), "blocklists/easyprivacy.txt");
+ final ArrayList<List<String[]>> fanboyAnnoyance = blockListHelper.parseBlockList(getAssets(), "blocklists/fanboy-annoyance.txt");
+ final ArrayList<List<String[]>> 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.
+ @SuppressWarnings("deprecation")
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ if (url.startsWith("mailto:")) { // Load the email address in an external email program.
+ // Use `ACTION_SENDTO` instead of `ACTION_SEND` so that only email programs are launched.
+ Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
+
+ // Parse the url and set it as the data for the `Intent`.
+ emailIntent.setData(Uri.parse(url));
+
+ // `FLAG_ACTIVITY_NEW_TASK` opens the email program in a new task instead as part of Privacy Browser.
+ emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- 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);
+ // Make it so.
+ startActivity(emailIntent);
- // Return an empty `WebResourceResponse`.
- return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
- }
- }
+ // Returning `true` indicates the application is handling the URL.
+ return true;
+ } else if (url.startsWith("tel:")) { // Load the phone number in the dialer.
+ // `ACTION_DIAL` open the dialer and loads the phone number, but waits for the user to place the call.
+ Intent dialIntent = new Intent(Intent.ACTION_DIAL);
- 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);
+ // Add the phone number to the intent.
+ dialIntent.setData(Uri.parse(url));
- // Return an empty `WebResourceResponse`.
- return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
- }
- }
+ // `FLAG_ACTIVITY_NEW_TASK` opens the dialer in a new task instead as part of Privacy Browser.
+ dialIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- 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);
+ // Make it so.
+ startActivity(dialIntent);
- // Return an empty `WebResourceResponse`.
- return new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes()));
- }
- }
+ // Returning `true` indicates the application is handling the URL.
+ return true;
+ } else { // Load the URL in Privacy Browser.
+ // Apply the domain settings for the new URL.
+ applyDomainSettings(url);
- 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);
+ // Returning `false` causes the current `WebView` to handle the URL and prevents it from adding redirects to the history list.
+ return false;
+ }
+ }
- // 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 : 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 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 : 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()));
- }
+ // 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;
+ }
+ } 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.
// 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);
}
// 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 (Build.VERSION.SDK_INT >= 21) {
+ cookieManager.flush();
+ }
+
// Reset `urlIsLoading`, which is used to prevent reloads on redirect if the user agent changes.
urlIsLoading = false;
!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));
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.
}
});
- // 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);
}
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);
}
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);
/* 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.
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;