+ // 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. `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 the privacy settings variables.
+ javaScriptEnabled = false;
+ firstPartyCookiesEnabled = false;
+ thirdPartyCookiesEnabled = false;
+ domStorageEnabled = false;
+ saveFormDataEnabled = false; // Form data can be removed once the minimum API >= 26.
+ nightMode = false;
+
+ // Store the default user agent.
+ webViewDefaultUserAgent = mainWebView.getSettings().getUserAgentString();
+
+ // Initialize the WebView title.
+ webViewTitle = getString(R.string.no_title);
+
+ // Initialize the favorite icon bitmap. `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;
+ }
+
+ // Initialize the user agent array adapter and string array.
+ userAgentNamesArray = ArrayAdapter.createFromResource(this, R.array.user_agent_names, R.layout.domain_settings_spinner_item);
+ userAgentDataArray = getResources().getStringArray(R.array.user_agent_data);
+
+ // Apply the app settings from the shared preferences.
+ applyAppSettings();
+
+ // Instantiate the block list helper.
+ BlockListHelper blockListHelper = new BlockListHelper();
+
+ // Initialize the list of resource requests.
+ resourceRequests = new ArrayList<>();
+
+ // 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[]>> fanboysAnnoyanceList = blockListHelper.parseBlockList(getAssets(), "blocklists/fanboy-annoyance.txt");
+ final ArrayList<List<String[]>> fanboysSocialList = blockListHelper.parseBlockList(getAssets(), "blocklists/fanboy-social.txt");
+ final ArrayList<List<String[]>> ultraPrivacy = blockListHelper.parseBlockList(getAssets(), "blocklists/ultraprivacy.txt");
+
+ // Store the list versions.
+ easyListVersion = easyList.get(0).get(0)[0];
+ easyPrivacyVersion = easyPrivacy.get(0).get(0)[0];
+ fanboysAnnoyanceVersion = fanboysAnnoyanceList.get(0).get(0)[0];
+ fanboysSocialVersion = fanboysSocialList.get(0).get(0)[0];
+ ultraPrivacyVersion = ultraPrivacy.get(0).get(0)[0];
+
+ // Get a handle for the activity. This is used to update the requests counter while the navigation menu is open.
+ Activity activity = this;
+
+ 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.
+ // The deprecated `shouldOverrideUrlLoading` must be used until API >= 24.
+ @SuppressWarnings("deprecation")
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ if (url.startsWith("http")) { // Load the URL in Privacy Browser.
+ // Reset the formatted URL string so the page will load correctly if blocking of third-party requests is enabled.
+ formattedUrlString = "";
+
+ // Apply the domain settings for the new URL. `applyDomainSettings` doesn't do anything if the domain has not changed.
+ applyDomainSettings(url, true, false);
+
+ // Returning false causes the current WebView to handle the URL and prevents it from adding redirects to the history list.
+ return false;
+ } else 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));
+
+ // Open the email program in a new task instead of as part of Privacy Browser.
+ emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Make it so.
+ startActivity(emailIntent);
+
+ // Returning true indicates Privacy Browser is handling the URL by creating an intent.
+ return true;
+ } else if (url.startsWith("tel:")) { // Load the phone number in the dialer.
+ // Open the dialer and load the phone number, but wait for the user to place the call.
+ Intent dialIntent = new Intent(Intent.ACTION_DIAL);
+
+ // Add the phone number to the intent.
+ dialIntent.setData(Uri.parse(url));
+
+ // Open the dialer in a new task instead of as part of Privacy Browser.
+ dialIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Make it so.
+ startActivity(dialIntent);
+
+ // Returning true indicates Privacy Browser is handling the URL by creating an intent.
+ return true;
+ } else { // Load a system chooser to select an app that can handle the URL.
+ // Open an app that can handle the URL.
+ Intent genericIntent = new Intent(Intent.ACTION_VIEW);
+
+ // Add the URL to the intent.
+ genericIntent.setData(Uri.parse(url));
+
+ // List all apps that can handle the URL instead of just opening the first one.
+ genericIntent.addCategory(Intent.CATEGORY_BROWSABLE);
+
+ // Open the app in a new task instead of as part of Privacy Browser.
+ genericIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Start the app or display a snackbar if no app is available to handle the URL.
+ try {
+ startActivity(genericIntent);
+ } catch (ActivityNotFoundException exception) {
+ Snackbar.make(mainWebView, getString(R.string.unrecognized_url) + " " + url, Snackbar.LENGTH_SHORT).show();