+ // Reload the current WebView.
+ currentWebView.reload();
+ } // Else do nothing because SDK < 21.
+ return true;
+
+ case R.id.toggle_dom_storage:
+ // Switch the status of domStorageEnabled.
+ domStorageEnabled = !domStorageEnabled;
+
+ // Update the menu checkbox.
+ menuItem.setChecked(domStorageEnabled);
+
+ // Apply the new DOM Storage status.
+ currentWebView.getSettings().setDomStorageEnabled(domStorageEnabled);
+
+ // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step.
+ updatePrivacyIcons(true);
+
+ // Display a `Snackbar`.
+ if (domStorageEnabled) {
+ Snackbar.make(findViewById(R.id.webviewpager), R.string.dom_storage_enabled, Snackbar.LENGTH_SHORT).show();
+ } else {
+ Snackbar.make(findViewById(R.id.webviewpager), R.string.dom_storage_disabled, Snackbar.LENGTH_SHORT).show();
+ }
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ // Form data can be removed once the minimum API >= 26.
+ case R.id.toggle_save_form_data:
+ // Switch the status of saveFormDataEnabled.
+ saveFormDataEnabled = !saveFormDataEnabled;
+
+ // Update the menu checkbox.
+ menuItem.setChecked(saveFormDataEnabled);
+
+ // Apply the new form data status.
+ currentWebView.getSettings().setSaveFormData(saveFormDataEnabled);
+
+ // Display a `Snackbar`.
+ if (saveFormDataEnabled) {
+ Snackbar.make(findViewById(R.id.webviewpager), R.string.form_data_enabled, Snackbar.LENGTH_SHORT).show();
+ } else {
+ Snackbar.make(findViewById(R.id.webviewpager), R.string.form_data_disabled, Snackbar.LENGTH_SHORT).show();
+ }
+
+ // Update the privacy icon. `true` runs `invalidateOptionsMenu` as the last step.
+ updatePrivacyIcons(true);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.clear_cookies:
+ Snackbar.make(findViewById(R.id.webviewpager), R.string.cookies_deleted, Snackbar.LENGTH_LONG)
+ .setAction(R.string.undo, v -> {
+ // Do nothing because everything will be handled by `onDismissed()` below.
+ })
+ .addCallback(new Snackbar.Callback() {
+ @SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`.
+ @Override
+ public void onDismissed(Snackbar snackbar, int event) {
+ switch (event) {
+ // The user pushed the undo button.
+ case Snackbar.Callback.DISMISS_EVENT_ACTION:
+ // Do nothing.
+ break;
+
+ // The snackbar was dismissed without the undo button being pushed.
+ default:
+ // `cookieManager.removeAllCookie()` varies by SDK.
+ if (Build.VERSION.SDK_INT < 21) {
+ cookieManager.removeAllCookie();
+ } else {
+ cookieManager.removeAllCookies(null);
+ }
+ }
+ }
+ })
+ .show();
+ return true;
+
+ case R.id.clear_dom_storage:
+ Snackbar.make(findViewById(R.id.webviewpager), R.string.dom_storage_deleted, Snackbar.LENGTH_LONG)
+ .setAction(R.string.undo, v -> {
+ // Do nothing because everything will be handled by `onDismissed()` below.
+ })
+ .addCallback(new Snackbar.Callback() {
+ @SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`.
+ @Override
+ public void onDismissed(Snackbar snackbar, int event) {
+ switch (event) {
+ // The user pushed the undo button.
+ case Snackbar.Callback.DISMISS_EVENT_ACTION:
+ // Do nothing.
+ break;
+
+ // The snackbar was dismissed without the undo button being pushed.
+ default:
+ // Delete the DOM Storage.
+ WebStorage webStorage = WebStorage.getInstance();
+ webStorage.deleteAllData();
+
+ // Initialize a handler to manually delete the DOM storage files and directories.
+ Handler deleteDomStorageHandler = new Handler();
+
+ // Setup a runnable to manually delete the DOM storage files and directories.
+ Runnable deleteDomStorageRunnable = () -> {
+ try {
+ // A string array must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly.
+ Process deleteLocalStorageProcess = privacyBrowserRuntime.exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"});
+
+ // Multiple commands must be used because `Runtime.exec()` does not like `*`.
+ Process deleteIndexProcess = privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB");
+ Process deleteQuotaManagerProcess = privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager");
+ Process deleteQuotaManagerJournalProcess = privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal");
+ Process deleteDatabasesProcess = privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases");
+
+ // Wait for the processes to finish.
+ deleteLocalStorageProcess.waitFor();
+ deleteIndexProcess.waitFor();
+ deleteQuotaManagerProcess.waitFor();
+ deleteQuotaManagerJournalProcess.waitFor();
+ deleteDatabasesProcess.waitFor();
+ } catch (Exception exception) {
+ // Do nothing if an error is thrown.
+ }
+ };
+
+ // Manually delete the DOM storage files after 200 milliseconds.
+ deleteDomStorageHandler.postDelayed(deleteDomStorageRunnable, 200);
+ }
+ }
+ })
+ .show();
+ return true;
+
+ // Form data can be remove once the minimum API >= 26.
+ case R.id.clear_form_data:
+ Snackbar.make(findViewById(R.id.webviewpager), R.string.form_data_deleted, Snackbar.LENGTH_LONG)
+ .setAction(R.string.undo, v -> {
+ // Do nothing because everything will be handled by `onDismissed()` below.
+ })
+ .addCallback(new Snackbar.Callback() {
+ @SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`.
+ @Override
+ public void onDismissed(Snackbar snackbar, int event) {
+ switch (event) {
+ // The user pushed the undo button.
+ case Snackbar.Callback.DISMISS_EVENT_ACTION:
+ // Do nothing.
+ break;
+
+ // The snackbar was dismissed without the `Undo` button being pushed.
+ default:
+ // Delete the form data.
+ WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(getApplicationContext());
+ mainWebViewDatabase.clearFormData();
+ }
+ }
+ })
+ .show();
+ return true;
+
+ case R.id.easylist:
+ // Toggle the EasyList status.
+ easyListEnabled = !easyListEnabled;
+
+ // Update the menu checkbox.
+ menuItem.setChecked(easyListEnabled);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.easyprivacy:
+ // Toggle the EasyPrivacy status.
+ easyPrivacyEnabled = !easyPrivacyEnabled;
+
+ // Update the menu checkbox.
+ menuItem.setChecked(easyPrivacyEnabled);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.fanboys_annoyance_list:
+ // Toggle Fanboy's Annoyance List status.
+ fanboysAnnoyanceListEnabled = !fanboysAnnoyanceListEnabled;
+
+ // Update the menu checkbox.
+ menuItem.setChecked(fanboysAnnoyanceListEnabled);
+
+ // Update the staus of Fanboy's Social Blocking List.
+ MenuItem fanboysSocialBlockingListMenuItem = mainMenu.findItem(R.id.fanboys_social_blocking_list);
+ fanboysSocialBlockingListMenuItem.setEnabled(!fanboysAnnoyanceListEnabled);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.fanboys_social_blocking_list:
+ // Toggle Fanboy's Social Blocking List status.
+ fanboysSocialBlockingListEnabled = !fanboysSocialBlockingListEnabled;
+
+ // Update the menu checkbox.
+ menuItem.setChecked(fanboysSocialBlockingListEnabled);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.ultraprivacy:
+ // Toggle the UltraPrivacy status.
+ ultraPrivacyEnabled = !ultraPrivacyEnabled;
+
+ // Update the menu checkbox.
+ menuItem.setChecked(ultraPrivacyEnabled);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.block_all_third_party_requests:
+ //Toggle the third-party requests blocker status.
+ blockAllThirdPartyRequests = !blockAllThirdPartyRequests;
+
+ // Update the menu checkbox.
+ menuItem.setChecked(blockAllThirdPartyRequests);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_privacy_browser:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[0]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_webview_default:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString("");
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_firefox_on_android:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[2]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_chrome_on_android:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[3]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_safari_on_ios:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[4]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_firefox_on_linux:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[5]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_chromium_on_linux:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[6]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_firefox_on_windows:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[7]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_chrome_on_windows:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[8]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_edge_on_windows:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[9]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_internet_explorer_on_windows:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[10]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_safari_on_macos:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(getResources().getStringArray(R.array.user_agent_data)[11]);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.user_agent_custom:
+ // Update the user agent.
+ currentWebView.getSettings().setUserAgentString(defaultCustomUserAgentString);
+
+ // Reload the current WebView.
+ currentWebView.reload();
+ return true;
+
+ case R.id.font_size_twenty_five_percent:
+ currentWebView.getSettings().setTextZoom(25);
+ return true;
+
+ case R.id.font_size_fifty_percent:
+ currentWebView.getSettings().setTextZoom(50);
+ return true;
+
+ case R.id.font_size_seventy_five_percent:
+ currentWebView.getSettings().setTextZoom(75);
+ return true;
+
+ case R.id.font_size_one_hundred_percent:
+ currentWebView.getSettings().setTextZoom(100);
+ return true;
+
+ case R.id.font_size_one_hundred_twenty_five_percent:
+ currentWebView.getSettings().setTextZoom(125);
+ return true;