- // Remove the lint warning below that the input method manager might be null.
- assert inputMethodManager != null;
-
- // Display the keyboard. `0` sets no input flags.
- inputMethodManager.showSoftInput(findOnPageEditText, 0);
- }, 200);
- return true;
-
- case R.id.view_source:
- // Create an intent to launch the view source activity.
- Intent viewSourceIntent = new Intent(this, ViewSourceActivity.class);
-
- // Add the variables to the intent.
- viewSourceIntent.putExtra("user_agent", currentWebView.getSettings().getUserAgentString());
- viewSourceIntent.putExtra("current_url", currentWebView.getUrl());
-
- // Make it so.
- startActivity(viewSourceIntent);
- return true;
-
- case R.id.share_url:
- // Setup the share string.
- String shareString = currentWebView.getTitle() + " – " + currentWebView.getUrl();
-
- // Create the share intent.
- Intent shareIntent = new Intent(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_TEXT, shareString);
- shareIntent.setType("text/plain");
-
- // Make it so.
- startActivity(Intent.createChooser(shareIntent, getString(R.string.share_url)));
- return true;
-
- case R.id.print:
- // Get a print manager instance.
- PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
-
- // Remove the lint error below that print manager might be null.
- assert printManager != null;
-
- // Create a print document adapter from the current WebView.
- PrintDocumentAdapter printDocumentAdapter = currentWebView.createPrintDocumentAdapter();
-
- // Print the document.
- printManager.print(getString(R.string.privacy_browser_web_page), printDocumentAdapter, null);
- return true;
-
- case R.id.open_with_app:
- openWithApp(currentWebView.getUrl());
- return true;
-
- case R.id.open_with_browser:
- openWithBrowser(currentWebView.getUrl());
- return true;
-
- case R.id.add_to_homescreen:
- // Instantiate the create home screen shortcut dialog.
- DialogFragment createHomeScreenShortcutDialogFragment = CreateHomeScreenShortcutDialog.createDialog(currentWebView.getTitle(), currentWebView.getUrl(),
- currentWebView.getFavoriteOrDefaultIcon());
-
- // Show the create home screen shortcut dialog.
- createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getString(R.string.create_shortcut));
- return true;
-
- case R.id.proxy_through_orbot:
- // Toggle the proxy through Orbot variable.
- proxyThroughOrbot = !proxyThroughOrbot;
-
- // Apply the proxy through Orbot settings.
- applyProxyThroughOrbot(true);
- return true;
-
- case R.id.refresh:
- if (menuItem.getTitle().equals(getString(R.string.refresh))) { // The refresh button was pushed.
- // Reload the current WebView.
- currentWebView.reload();
- } else { // The stop button was pushed.
- // Stop the loading of the WebView.
- currentWebView.stopLoading();
- }
- return true;
-
- case R.id.ad_consent:
- // Display the ad consent dialog.
- DialogFragment adConsentDialogFragment = new AdConsentDialog();
- adConsentDialogFragment.show(getSupportFragmentManager(), getString(R.string.ad_consent));
- return true;
-
- default:
- // Don't consume the event.
- return super.onOptionsItemSelected(menuItem);
- }
- }
-
- // removeAllCookies is deprecated, but it is required for API < 21.
- @SuppressWarnings("deprecation")
- @Override
- public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
- // Get the menu item ID.
- int menuItemId = menuItem.getItemId();
-
- // Get a handle for the shared preferences.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
-
- // Run the commands that correspond to the selected menu item.
- switch (menuItemId) {
- case R.id.close_tab:
- // Get a handle for the tab layout and the view pager.
- TabLayout tabLayout = findViewById(R.id.tablayout);
- ViewPager webViewPager = findViewById(R.id.webviewpager);
-
- // Get the current tab number.
- int currentTabNumber = tabLayout.getSelectedTabPosition();
-
- // Delete the current tab.
- tabLayout.removeTabAt(currentTabNumber);
-
- // Delete the current page. If the selected page number did not change during the delete, it will return true, meaning that the current WebView must be reset.
- if (webViewPagerAdapter.deletePage(currentTabNumber, webViewPager)) {
- setCurrentWebView(currentTabNumber);
- }
- break;
-
- case R.id.clear_and_exit:
- // Close the bookmarks cursor and database.
- bookmarksCursor.close();
- bookmarksDatabaseHelper.close();
-
- // Get the status of the clear everything preference.
- boolean clearEverything = sharedPreferences.getBoolean("clear_everything", true);
-
- // Get a handle for the runtime.
- Runtime runtime = Runtime.getRuntime();
-
- // Clear cookies.
- if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) {
- // The command to remove cookies changed slightly in API 21.
- if (Build.VERSION.SDK_INT >= 21) {
- CookieManager.getInstance().removeAllCookies(null);
- } else {
- CookieManager.getInstance().removeAllCookie();
- }
-
- // Manually delete the cookies database, as `CookieManager` sometimes will not flush its changes to disk before `System.exit(0)` is run.
- try {
- // Two commands must be used because `Runtime.exec()` does not like `*`.
- Process deleteCookiesProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/Cookies");
- Process deleteCookiesJournalProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/Cookies-journal");
-
- // Wait until the processes have finished.
- deleteCookiesProcess.waitFor();
- deleteCookiesJournalProcess.waitFor();
- } catch (Exception exception) {
- // Do nothing if an error is thrown.
- }
- }
-
- // Clear DOM storage.
- if (clearEverything || sharedPreferences.getBoolean("clear_dom_storage", true)) {
- // Ask `WebStorage` to clear the DOM storage.
- WebStorage webStorage = WebStorage.getInstance();
- webStorage.deleteAllData();
-
- // Manually delete the DOM storage files and directories, as `WebStorage` sometimes will not flush its changes to disk before `System.exit(0)` is run.
- try {
- // A `String[]` must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly.
- Process deleteLocalStorageProcess = runtime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"});
-
- // Multiple commands must be used because `Runtime.exec()` does not like `*`.
- Process deleteIndexProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB");
- Process deleteQuotaManagerProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager");
- Process deleteQuotaManagerJournalProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal");
- Process deleteDatabaseProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases");
-
- // Wait until the processes have finished.
- deleteLocalStorageProcess.waitFor();
- deleteIndexProcess.waitFor();
- deleteQuotaManagerProcess.waitFor();
- deleteQuotaManagerJournalProcess.waitFor();
- deleteDatabaseProcess.waitFor();
- } catch (Exception exception) {
- // Do nothing if an error is thrown.
- }
- }
-
- // Clear form data if the API < 26.
- if ((Build.VERSION.SDK_INT < 26) && (clearEverything || sharedPreferences.getBoolean("clear_form_data", true))) {
- WebViewDatabase webViewDatabase = WebViewDatabase.getInstance(this);
- webViewDatabase.clearFormData();
-
- // Manually delete the form data database, as `WebViewDatabase` sometimes will not flush its changes to disk before `System.exit(0)` is run.
- try {
- // A string array must be used because the database contains a space and `Runtime.exec` will not otherwise escape the string correctly.
- Process deleteWebDataProcess = runtime.exec(new String[] {"rm", "-f", privateDataDirectoryString + "/app_webview/Web Data"});
- Process deleteWebDataJournalProcess = runtime.exec(new String[] {"rm", "-f", privateDataDirectoryString + "/app_webview/Web Data-journal"});
-
- // Wait until the processes have finished.
- deleteWebDataProcess.waitFor();
- deleteWebDataJournalProcess.waitFor();
- } catch (Exception exception) {
- // Do nothing if an error is thrown.
- }
- }
-
- // Clear the cache.
- if (clearEverything || sharedPreferences.getBoolean("clear_cache", true)) {
- // Clear the cache from each WebView.
- for (int i = 0; i < webViewPagerAdapter.getCount(); i++) {
- // Get the WebView tab fragment.
- WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i);
-
- // Get the fragment view.
- View fragmentView = webViewTabFragment.getView();
-
- // Only clear the cache if the WebView exists.
- if (fragmentView != null) {
- // Get the nested scroll WebView from the tab fragment.
- NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
-
- // Clear the cache for this WebView.
- nestedScrollWebView.clearCache(true);
- }
- }
-
- // Manually delete the cache directories.
- try {
- // Delete the main cache directory.
- Process deleteCacheProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/cache");
-
- // Delete the secondary `Service Worker` cache directory.
- // A string array must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly.
- Process deleteServiceWorkerProcess = runtime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"});
-
- // Wait until the processes have finished.
- deleteCacheProcess.waitFor();
- deleteServiceWorkerProcess.waitFor();
- } catch (Exception exception) {
- // Do nothing if an error is thrown.
- }
- }
-
- // Wipe out each WebView.
- for (int i = 0; i < webViewPagerAdapter.getCount(); i++) {
- // Get the WebView tab fragment.
- WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i);
-
- // Get the fragment view.
- View fragmentView = webViewTabFragment.getView();
-
- // Only wipe out the WebView if it exists.
- if (fragmentView != null) {
- // Get the nested scroll WebView from the tab fragment.
- NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
-
- // Clear SSL certificate preferences for this WebView.
- nestedScrollWebView.clearSslPreferences();
-
- // Clear the back/forward history for this WebView.
- nestedScrollWebView.clearHistory();
-
- // Destroy the internal state of `mainWebView`.
- nestedScrollWebView.destroy();
- }
- }
-
- // Clear the custom headers.
- customHeaders.clear();
-
- // Manually delete the `app_webview` folder, which contains the cookies, DOM storage, form data, and `Service Worker` cache.
- // See `https://code.google.com/p/android/issues/detail?id=233826&thanks=233826&ts=1486670530`.
- if (clearEverything) {
- try {
- // Delete the folder.
- Process deleteAppWebviewProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview");
-
- // Wait until the process has finished.
- deleteAppWebviewProcess.waitFor();
- } catch (Exception exception) {
- // Do nothing if an error is thrown.
- }
- }
-
- // Close Privacy Browser. `finishAndRemoveTask` also removes Privacy Browser from the recent app list.
- if (Build.VERSION.SDK_INT >= 21) {
- finishAndRemoveTask();
- } else {
- finish();
- }
-
- // Remove the terminated program from RAM. The status code is `0`.
- System.exit(0);
- break;
-
- case R.id.home:
- // Select the homepage based on the proxy through Orbot status.
- if (proxyThroughOrbot) {
- // Load the Tor homepage.
- loadUrl(sharedPreferences.getString("tor_homepage", getString(R.string.tor_homepage_default_value)));
- } else {
- // Load the normal homepage.
- loadUrl(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value)));
- }
- break;
-
- case R.id.back:
- if (currentWebView.canGoBack()) {
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- currentWebView.resetCurrentDomainName();
-
- // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded.
- navigatingHistory = true;
-
- // Load the previous website in the history.
- currentWebView.goBack();
- }
- break;
-
- case R.id.forward:
- if (currentWebView.canGoForward()) {
- // Reset the current domain name so that navigation works if third-party requests are blocked.
- currentWebView.resetCurrentDomainName();
-
- // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded.
- navigatingHistory = true;
-
- // Load the next website in the history.
- currentWebView.goForward();
- }
- break;
-
- case R.id.history:
- // Get the `WebBackForwardList`.
- WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
-
- // Show the URL history dialog and name this instance `R.string.history`.
- DialogFragment urlHistoryDialogFragment = UrlHistoryDialog.loadBackForwardList(this, webBackForwardList);
- urlHistoryDialogFragment.show(getSupportFragmentManager(), getString(R.string.history));
- break;
-
- case R.id.requests:
- // Populate the resource requests.
- RequestsActivity.resourceRequests = currentWebView.getResourceRequests();
-
- // Create an intent to launch the Requests activity.
- Intent requestsIntent = new Intent(this, RequestsActivity.class);
-
- // Add the block third-party requests status to the intent.
- requestsIntent.putExtra("block_all_third_party_requests", currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS));
-
- // Make it so.
- startActivity(requestsIntent);
- break;
-
- case R.id.downloads:
- // Launch the system Download Manager.
- Intent downloadManagerIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
-
- // Launch as a new task so that Download Manager and Privacy Browser show as separate windows in the recent tasks list.
- downloadManagerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- startActivity(downloadManagerIntent);
- break;
-
- case R.id.domains:
- // Set the flag to reapply the domain settings on restart when returning from Domain Settings.
- reapplyDomainSettingsOnRestart = true;
-
- // TODO. Move these to `putExtra`. The certificate can be stored as strings.
- // Store the current SSL certificate and IP addresses in the domains activity.
- DomainsActivity.currentSslCertificate = currentWebView.getCertificate();
- DomainsActivity.currentIpAddresses = currentWebView.getCurrentIpAddresses();
-
- // Launch the domains activity.
- Intent domainsIntent = new Intent(this, DomainsActivity.class);
-
- // Add the extra information to the intent.
- domainsIntent.putExtra("current_url", currentWebView.getUrl());
-
- // Make it so.
- startActivity(domainsIntent);
- break;
-
- case R.id.settings:
- // Set the flag to reapply app settings on restart when returning from Settings.
- reapplyAppSettingsOnRestart = true;
-
- // Set the flag to reapply the domain settings on restart when returning from Settings.
- reapplyDomainSettingsOnRestart = true;
-
- // Launch the settings activity.
- Intent settingsIntent = new Intent(this, SettingsActivity.class);
- startActivity(settingsIntent);
- break;