- // Select the current user agent menu item. A switch statement cannot be used because the user agents are not compile time constants.
- if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[0])) { // Privacy Browser.
- menu.findItem(R.id.user_agent_privacy_browser).setChecked(true);
- } else if (currentUserAgent.equals(webViewDefaultUserAgent)) { // WebView Default.
- menu.findItem(R.id.user_agent_webview_default).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[2])) { // Firefox on Android.
- menu.findItem(R.id.user_agent_firefox_on_android).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[3])) { // Chrome on Android.
- menu.findItem(R.id.user_agent_chrome_on_android).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[4])) { // Safari on iOS.
- menu.findItem(R.id.user_agent_safari_on_ios).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[5])) { // Firefox on Linux.
- menu.findItem(R.id.user_agent_firefox_on_linux).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[6])) { // Chromium on Linux.
- menu.findItem(R.id.user_agent_chromium_on_linux).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[7])) { // Firefox on Windows.
- menu.findItem(R.id.user_agent_firefox_on_windows).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[8])) { // Chrome on Windows.
- menu.findItem(R.id.user_agent_chrome_on_windows).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[9])) { // Edge on Windows.
- menu.findItem(R.id.user_agent_edge_on_windows).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[10])) { // Internet Explorer on Windows.
- menu.findItem(R.id.user_agent_internet_explorer_on_windows).setChecked(true);
- } else if (currentUserAgent.equals(getResources().getStringArray(R.array.user_agent_data)[11])) { // Safari on macOS.
- menu.findItem(R.id.user_agent_safari_on_macos).setChecked(true);
- } else { // Custom user agent.
- menu.findItem(R.id.user_agent_custom).setChecked(true);
+ // 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 = privacyBrowserRuntime.exec(new String[] {"rm", "-f", privateDataDirectoryString + "/app_webview/Web Data"});
+ Process deleteWebDataJournalProcess = privacyBrowserRuntime.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.
+ // TODO
+ currentWebView.clearCache(true);
+
+ // Manually delete the cache directories.
+ try {
+ // Delete the main cache directory.
+ Process deleteCacheProcess = privacyBrowserRuntime.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 = privacyBrowserRuntime.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.
+ }
+ }
+
+ // Clear SSL certificate preferences.
+ // TODO
+ currentWebView.clearSslPreferences();
+
+ // Clear the back/forward history.
+ // TODO
+ currentWebView.clearHistory();
+
+ // Clear `formattedUrlString`.
+ formattedUrlString = null;
+
+ // Clear `customHeaders`.
+ customHeaders.clear();
+
+ // Destroy the internal state of `mainWebView`.
+ // TODO
+ currentWebView.destroy();
+
+ // 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 = privacyBrowserRuntime.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:
+ loadUrl(homepage);
+ break;
+
+ case R.id.back:
+ if (currentWebView.canGoBack()) {
+ // Reset the formatted URL string so the page will load correctly if blocking of third-party requests is enabled.
+ formattedUrlString = "";
+
+ // 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 formatted URL string so the page will load correctly if blocking of third-party requests is enabled.
+ formattedUrlString = "";
+
+ // 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:
+ // Launch the requests activity.
+ Intent requestsIntent = new Intent(this, RequestsActivity.class);
+ 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;
+ currentDomainName = "";
+
+ // Launch the domains activity.
+ Intent domainsIntent = new Intent(this, DomainsActivity.class);
+ 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;
+ currentDomainName = "";
+
+ // Launch the settings activity.
+ Intent settingsIntent = new Intent(this, SettingsActivity.class);
+ startActivity(settingsIntent);
+ break;
+
+ case R.id.import_export:
+ // Launch the import/export activity.
+ Intent importExportIntent = new Intent (this, ImportExportActivity.class);
+ startActivity(importExportIntent);
+ break;
+
+ case R.id.logcat:
+ // Launch the logcat activity.
+ Intent logcatIntent = new Intent(this, LogcatActivity.class);
+ startActivity(logcatIntent);
+ break;
+
+ case R.id.guide:
+ // Launch `GuideActivity`.
+ Intent guideIntent = new Intent(this, GuideActivity.class);
+ startActivity(guideIntent);
+ break;
+
+ case R.id.about:
+ // Launch `AboutActivity`.
+ Intent aboutIntent = new Intent(this, AboutActivity.class);
+ startActivity(aboutIntent);
+ break;
+ }
+
+ // Get a handle for the drawer layout.
+ DrawerLayout drawerLayout = findViewById(R.id.drawerlayout);
+
+ // Close the navigation drawer.
+ drawerLayout.closeDrawer(GravityCompat.START);
+ return true;
+ }
+
+ @Override
+ public void onPostCreate(Bundle savedInstanceState) {
+ // Run the default commands.
+ super.onPostCreate(savedInstanceState);
+
+ // Sync the state of the DrawerToggle after the default `onRestoreInstanceState()` has finished. This creates the navigation drawer icon.
+ actionBarDrawerToggle.syncState();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ // Run the default commands.
+ super.onConfigurationChanged(newConfig);
+
+ // Get the status bar pixel size.
+ int statusBarResourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
+ int statusBarPixelSize = getResources().getDimensionPixelSize(statusBarResourceId);
+
+ // Get the resource density.
+ float screenDensity = getResources().getDisplayMetrics().density;
+
+ // Recalculate the drawer header padding.
+ drawerHeaderPaddingLeftAndRight = (int) (15 * screenDensity);
+ drawerHeaderPaddingTop = statusBarPixelSize + (int) (4 * screenDensity);
+ drawerHeaderPaddingBottom = (int) (8 * screenDensity);
+
+ // Reload the ad for the free flavor if not in full screen mode.
+ if (BuildConfig.FLAVOR.contentEquals("free") && !inFullScreenBrowsingMode) {
+ // Reload the ad. The AdView is destroyed and recreated, which changes the ID, every time it is reloaded to handle possible rotations.
+ AdHelper.loadAd(findViewById(R.id.adview), getApplicationContext(), getString(R.string.ad_unit_id));