X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Factivities%2FMainWebViewActivity.java;h=2b9ad6376d95ea13ab2b23eed18fba1de73534c3;hp=c2d169b40b7ee0d0ebdad343e352b672d3d469ab;hb=a156c3942ca31a1afca3271245cc2bda7ed5aed8;hpb=c45c0fa64109c47bdc35328d0e31a65c685bdc22 diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index c2d169b4..2b9ad637 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -174,10 +174,8 @@ import java.text.NumberFormat; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -236,9 +234,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxy()`, and `applyDomainSettings()`. private NestedScrollWebView currentWebView; - // `customHeader` is used in `onCreate()`, `onOptionsItemSelected()`, `onCreateContextMenu()`, and `loadUrl()`. - private final Map customHeaders = new HashMap<>(); - // The search URL is set in `applyAppSettings()` and used in `onNewIntent()`, `loadUrlFromTextBox()`, `initializeApp()`, and `initializeWebView()`. private String searchURL; @@ -373,7 +368,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private Activity resultLauncherActivityHandle; // Define the save URL activity result launcher. It must be defined before `onCreate()` is run or the app will crash. - private final ActivityResultLauncher saveUrlActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(), + private final ActivityResultLauncher saveUrlActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument("text/*"), new ActivityResultCallback() { @Override public void onActivityResult(Uri fileUri) { @@ -388,7 +383,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook }); // Define the save webpage archive activity result launcher. It must be defined before `onCreate()` is run or the app will crash. - private final ActivityResultLauncher saveWebpageArchiveActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(), + private final ActivityResultLauncher saveWebpageArchiveActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument("multipart/related"), new ActivityResultCallback() { @Override public void onActivityResult(Uri fileUri) { @@ -465,7 +460,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook }); // Define the save webpage image activity result launcher. It must be defined before `onCreate()` is run or the app will crash. - private final ActivityResultLauncher saveWebpageImageActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(), + private final ActivityResultLauncher saveWebpageImageActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument("image/png"), new ActivityResultCallback() { @Override public void onActivityResult(Uri fileUri) { @@ -692,6 +687,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook drawerLayout.closeDrawer(GravityCompat.END); } } + } else { // The app has been restarted. + // Replace the intent that started the app with this one. This will load the tab after the others have been restored. + setIntent(intent); } } @@ -1058,8 +1056,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Enable DOM Storage if JavaScript is enabled. optionsDomStorageMenuItem.setEnabled(currentWebView.getSettings().getJavaScriptEnabled()); + // Get the current theme status. + int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + + // Enable dark WebView if the API is < 33 or if night mode is enabled. + optionsDarkWebViewMenuItem.setEnabled((Build.VERSION.SDK_INT < 33) || (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES)); + // Set the checkbox status for dark WebView if the WebView supports it. - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + if ((Build.VERSION.SDK_INT >= 33) && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { // The device is running API >= 33 and algorithmic darkening is supported. + optionsDarkWebViewMenuItem.setChecked(WebSettingsCompat.isAlgorithmicDarkeningAllowed(currentWebView.getSettings())); + } else if ((Build.VERSION.SDK_INT < 33) && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { // The device is running API < 33 and the WebView supports force dark. + //noinspection deprecation optionsDarkWebViewMenuItem.setChecked(WebSettingsCompat.getForceDark(currentWebView.getSettings()) == WebSettingsCompat.FORCE_DARK_ON); } } @@ -1685,7 +1692,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook return true; } else if (menuItemId == R.id.user_agent_custom) { // User Agent - Custom. // Update the user agent. - currentWebView.getSettings().setUserAgentString(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value))); + currentWebView.getSettings().setUserAgentString(sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))); // Reload the current WebView. currentWebView.reload(); @@ -1739,13 +1746,19 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook return true; } else if (menuItemId == R.id.dark_webview) { // Dark WebView. // Check to see if dark WebView is supported by this WebView. - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + if ((Build.VERSION.SDK_INT >= 33) && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { // The device is running API >= 33 and algorithmic darkening is supported. + // Toggle algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(currentWebView.getSettings(), !WebSettingsCompat.isAlgorithmicDarkeningAllowed(currentWebView.getSettings())); + } else if ((Build.VERSION.SDK_INT < 33) && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { // The device is running API < 33 and the WebView supports force dark. // Toggle the dark WebView setting. + //noinspection deprecation if (WebSettingsCompat.getForceDark(currentWebView.getSettings()) == WebSettingsCompat.FORCE_DARK_ON) { // Dark WebView is currently enabled. // Turn off dark WebView. + //noinspection deprecation WebSettingsCompat.setForceDark(currentWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); } else { // Dark WebView is currently disabled. // Turn on dark WebView. + //noinspection deprecation WebSettingsCompat.setForceDark(currentWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); } } @@ -1902,19 +1915,19 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Consume the event. return true; } else if (menuItemId == R.id.add_or_edit_domain) { // Add or edit domain. + // Reapply the domain settings on returning to `MainWebViewActivity`. + reapplyDomainSettingsOnRestart = true; + // Check if domain settings currently exist. if (currentWebView.getDomainSettingsApplied()) { // Edit the current domain settings. - // Reapply the domain settings on returning to `MainWebViewActivity`. - reapplyDomainSettingsOnRestart = true; - // Create an intent to launch the domains activity. Intent domainsIntent = new Intent(this, DomainsActivity.class); // Add the extra information to the intent. - domainsIntent.putExtra("load_domain", currentWebView.getDomainSettingsDatabaseId()); - domainsIntent.putExtra("close_on_back", true); - domainsIntent.putExtra("current_url", currentWebView.getUrl()); - domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses()); + domainsIntent.putExtra(DomainsActivity.LOAD_DOMAIN, currentWebView.getDomainSettingsDatabaseId()); + domainsIntent.putExtra(DomainsActivity.CLOSE_ON_BACK, true); + domainsIntent.putExtra(DomainsActivity.CURRENT_URL, currentWebView.getUrl()); + domainsIntent.putExtra(DomainsActivity.CURRENT_IP_ADDRESSES, currentWebView.getCurrentIpAddresses()); // Get the current certificate. SslCertificate sslCertificate = currentWebView.getCertificate(); @@ -1932,26 +1945,29 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook long endDateLong = sslCertificate.getValidNotAfterDate().getTime(); // Add the certificate to the intent. - domainsIntent.putExtra("ssl_issued_to_cname", issuedToCName); - domainsIntent.putExtra("ssl_issued_to_oname", issuedToOName); - domainsIntent.putExtra("ssl_issued_to_uname", issuedToUName); - domainsIntent.putExtra("ssl_issued_by_cname", issuedByCName); - domainsIntent.putExtra("ssl_issued_by_oname", issuedByOName); - domainsIntent.putExtra("ssl_issued_by_uname", issuedByUName); - domainsIntent.putExtra("ssl_start_date", startDateLong); - domainsIntent.putExtra("ssl_end_date", endDateLong); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_TO_CNAME, issuedToCName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_TO_ONAME, issuedToOName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_TO_UNAME, issuedToUName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_BY_CNAME, issuedByCName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_BY_ONAME, issuedByOName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_BY_UNAME, issuedByUName); + domainsIntent.putExtra(DomainsActivity.SSL_START_DATE, startDateLong); + domainsIntent.putExtra(DomainsActivity.SSL_END_DATE, endDateLong); } // Make it so. startActivity(domainsIntent); } else { // Add a new domain. - // Apply the new domain settings on returning to `MainWebViewActivity`. - reapplyDomainSettingsOnRestart = true; - - // Get the current domain + // Get the current URI. Uri currentUri = Uri.parse(currentWebView.getUrl()); + + // Get the current domain from the URI. String currentDomain = currentUri.getHost(); + // Set an empty domain if it is null. + if (currentDomain == null) + currentDomain = ""; + // Create the domain and store the database ID. int newDomainDatabaseId = domainsDatabaseHelper.addDomain(currentDomain); @@ -1959,10 +1975,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook Intent domainsIntent = new Intent(this, DomainsActivity.class); // Add the extra information to the intent. - domainsIntent.putExtra("load_domain", newDomainDatabaseId); - domainsIntent.putExtra("close_on_back", true); - domainsIntent.putExtra("current_url", currentWebView.getUrl()); - domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses()); + domainsIntent.putExtra(DomainsActivity.LOAD_DOMAIN, newDomainDatabaseId); + domainsIntent.putExtra(DomainsActivity.CLOSE_ON_BACK, true); + domainsIntent.putExtra(DomainsActivity.CURRENT_URL, currentWebView.getUrl()); + domainsIntent.putExtra(DomainsActivity.CURRENT_IP_ADDRESSES, currentWebView.getCurrentIpAddresses()); // Get the current certificate. SslCertificate sslCertificate = currentWebView.getCertificate(); @@ -1980,14 +1996,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook long endDateLong = sslCertificate.getValidNotAfterDate().getTime(); // Add the certificate to the intent. - domainsIntent.putExtra("ssl_issued_to_cname", issuedToCName); - domainsIntent.putExtra("ssl_issued_to_oname", issuedToOName); - domainsIntent.putExtra("ssl_issued_to_uname", issuedToUName); - domainsIntent.putExtra("ssl_issued_by_cname", issuedByCName); - domainsIntent.putExtra("ssl_issued_by_oname", issuedByOName); - domainsIntent.putExtra("ssl_issued_by_uname", issuedByUName); - domainsIntent.putExtra("ssl_start_date", startDateLong); - domainsIntent.putExtra("ssl_end_date", endDateLong); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_TO_CNAME, issuedToCName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_TO_ONAME, issuedToOName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_TO_UNAME, issuedToUName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_BY_CNAME, issuedByCName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_BY_ONAME, issuedByOName); + domainsIntent.putExtra(DomainsActivity.SSL_ISSUED_BY_UNAME, issuedByUName); + domainsIntent.putExtra(DomainsActivity.SSL_START_DATE, startDateLong); + domainsIntent.putExtra(DomainsActivity.SSL_END_DATE, endDateLong); } // Make it so. @@ -2125,8 +2141,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook Intent domainsIntent = new Intent(this, DomainsActivity.class); // Add the extra information to the intent. - domainsIntent.putExtra("current_url", currentWebView.getUrl()); - domainsIntent.putExtra("current_ip_addresses", currentWebView.getCurrentIpAddresses()); + domainsIntent.putExtra(DomainsActivity.CURRENT_URL, currentWebView.getUrl()); + domainsIntent.putExtra(DomainsActivity.CURRENT_IP_ADDRESSES, currentWebView.getCurrentIpAddresses()); // Get the current certificate. SslCertificate sslCertificate = currentWebView.getCertificate(); @@ -3489,9 +3505,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } }); - // 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", ""); - // Inflate a bare WebView to get the default user agent. It is not used to render content on the screen. @SuppressLint("InflateParams") View webViewLayout = getLayoutInflater().inflate(R.layout.bare_webview, null, false); @@ -3783,12 +3796,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); // Store the general preference information. - String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value)); - String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value)); - boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true); - String webViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value)); - boolean wideViewport = sharedPreferences.getBoolean("wide_viewport", true); - boolean displayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true); + boolean defaultXRequestedWithHeader = sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true); + String defaultFontSizeString = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)); + String defaultUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value)); + boolean defaultSwipeToRefresh = sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true); + String webViewTheme = sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value)); + boolean wideViewport = sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true); + boolean displayWebpageImages = sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true); // Get the WebView theme entry values string array. String[] webViewThemeEntryValuesStringArray = getResources().getStringArray(R.array.webview_theme_entry_values); @@ -3819,13 +3833,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook boolean saveFormData = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_FORM_DATA)) == 1); nestedScrollWebView.setEasyListEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_EASYLIST)) == 1); nestedScrollWebView.setEasyPrivacyEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_EASYPRIVACY)) == 1); - nestedScrollWebView.setFanboysAnnoyanceListEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST)) == 1); + nestedScrollWebView.setFanboysAnnoyanceListEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow( + DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST)) == 1); nestedScrollWebView.setFanboysSocialBlockingListEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow( DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST)) == 1); nestedScrollWebView.setUltraListEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ULTRALIST)) == 1); nestedScrollWebView.setUltraPrivacyEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY)) == 1); - nestedScrollWebView.setBlockAllThirdPartyRequests(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS)) == 1); + nestedScrollWebView.setBlockAllThirdPartyRequests(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow( + DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS)) == 1); String userAgentName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.USER_AGENT)); + int xRequestedWithHeaderInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.X_REQUESTED_WITH_HEADER)); int fontSize = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.FONT_SIZE)); int swipeToRefreshInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SWIPE_TO_REFRESH)); int webViewThemeInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.WEBVIEW_THEME)); @@ -3865,6 +3882,24 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.getSettings().setSaveFormData(saveFormData); } + // Set the X-Requested-With header. + switch (xRequestedWithHeaderInt) { + case DomainsDatabaseHelper.SYSTEM_DEFAULT: + if (defaultXRequestedWithHeader) + nestedScrollWebView.setXRequestedWithHeader(); + else + nestedScrollWebView.resetXRequestedWithHeader(); + break; + + case DomainsDatabaseHelper.ENABLED: + nestedScrollWebView.setXRequestedWithHeader(); + break; + + case DomainsDatabaseHelper.DISABLED: + nestedScrollWebView.resetXRequestedWithHeader(); + break; + } + // Apply the font size. try { // Try the specified font size to see if it is valid. if (fontSize == 0) { // Apply the default font size. @@ -3897,7 +3932,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case SETTINGS_CUSTOM_USER_AGENT: // Set the default custom user agent. - nestedScrollWebView.getSettings().setUserAgentString(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value))); + nestedScrollWebView.getSettings().setUserAgentString(sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))); break; default: @@ -3954,19 +3989,52 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Disable swipe to refresh. swipeRefreshLayout.setEnabled(false); + break; } // Check to see if WebView themes are supported. - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + if ((Build.VERSION.SDK_INT >= 33) && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { // The device is running API >= 33 and algorithmic darkening is supported. + // Set the WebView theme. + switch (webViewThemeInt) { + case DomainsDatabaseHelper.SYSTEM_DEFAULT: + // Set the WebView theme. A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant. + if (webViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected. + // Turn off algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), false); + } else if (webViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected. + // Turn on algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), true); + } else { // The system default theme is selected. + // Get the current system theme status. + int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + + // Set the algorithmic darkening according to the current system theme status. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES)); + } + break; + + case DomainsDatabaseHelper.LIGHT_THEME: + // Turn off algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), false); + break; + + case DomainsDatabaseHelper.DARK_THEME: + // Turn on algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), true); + break; + } + } else if ((Build.VERSION.SDK_INT < 33) && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { // The device is running API < 33 and the WebView supports force dark. // Set the WebView theme. switch (webViewThemeInt) { case DomainsDatabaseHelper.SYSTEM_DEFAULT: // Set the WebView theme. A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant. if (webViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected. // Turn off the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); } else if (webViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected. // Turn on the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); } else { // The system default theme is selected. // Get the current system theme status. @@ -3975,9 +4043,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the WebView theme according to the current system theme status. if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { // The system is in day mode. // Turn off the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); } else { // The system is in night mode. // Turn on the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); } } @@ -3985,11 +4055,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case DomainsDatabaseHelper.LIGHT_THEME: // Turn off the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); break; case DomainsDatabaseHelper.DARK_THEME: // Turn on the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); break; } @@ -4058,6 +4130,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.getSettings().setSaveFormData(saveFormData); } + // Store the X-Requested-With header status in the nested scroll WebView. + if (defaultXRequestedWithHeader) + nestedScrollWebView.setXRequestedWithHeader(); + else + nestedScrollWebView.resetXRequestedWithHeader(); + // Store the swipe to refresh status in the nested scroll WebView. nestedScrollWebView.setSwipeToRefresh(defaultSwipeToRefresh); @@ -4090,7 +4168,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case SETTINGS_CUSTOM_USER_AGENT: // Set the default custom user agent. - nestedScrollWebView.getSettings().setUserAgentString(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value))); + nestedScrollWebView.getSettings().setUserAgentString(sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))); break; default: @@ -4099,13 +4177,30 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Apply the WebView theme if supported by the installed WebView. - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + if ((Build.VERSION.SDK_INT >= 33) && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { // The device is running API >= 33 and algorithmic darkening is supported. + // Set the WebView theme. A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant. + if (webViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // the light theme is selected. + // Turn off algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), false); + } else if (webViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected. + // Turn on algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), true); + } else { // The system default theme is selected. + // Get the current system theme status. + int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + + // Set the algorithmic darkening according to the current system theme status. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), currentThemeStatus == Configuration.UI_MODE_NIGHT_YES); + } + } else if ((Build.VERSION.SDK_INT < 33) && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { // The device is running API < 33 and the WebView supports force dark. // Set the WebView theme. A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant. if (webViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected. // Turn off the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); } else if (webViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected. // Turn on the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); } else { // The system default theme is selected. // Get the current system theme status. @@ -4114,9 +4209,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the WebView theme according to the current system theme status. if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { // The system is in day mode. // Turn off the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); } else { // The system is in night mode. // Turn on the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); } } @@ -4146,7 +4243,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Load the URL if directed. This makes sure that the domain settings are properly loaded before the URL. By using `loadUrl()`, instead of `loadUrlFromBase()`, the Referer header will never be sent. if (loadUrl) { - nestedScrollWebView.loadUrl(url, customHeaders); + nestedScrollWebView.loadUrl(url, nestedScrollWebView.getXRequestedWithHeader()); } } @@ -4831,7 +4928,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // 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/"}); + Process deleteServiceWorkerProcess = runtime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Default/Service Worker/"}); // Wait until the processes have finished. deleteCacheProcess.waitFor(); @@ -4868,9 +4965,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - // 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) { @@ -5006,16 +5100,46 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); // Get the WebView theme. - String webViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value)); + String webViewTheme = sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value)); // Get the WebView theme entry values string array. String[] webViewThemeEntryValuesStringArray = getResources().getStringArray(R.array.webview_theme_entry_values); // Apply the WebView theme if supported by the installed WebView. - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + if ((Build.VERSION.SDK_INT >= 33) && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { // The device is running API >= 33 and algorithmic darkening is supported. + // Set the WebView them. A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant. + if (webViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected. + // Turn off algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), false); + + // Make the WebView visible. The WebView was created invisible in `webview_framelayout` to prevent a white background splash in night mode. + // If the system is currently in night mode, showing the WebView will be handled in `onProgressChanged()`. + nestedScrollWebView.setVisibility(View.VISIBLE); + } else if (webViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected. + // Turn on algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), true); + } else { + // The system default theme is selected. + int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + + // Set the algorithmic darkening according to the current system theme status. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { // The system is in day mode. + // Turn off algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), false); + + // Make the WebView visible. The WebView was created invisible in `webview_framelayout` to prevent a white background splash in night mode. + // If the system is currently in night mode, showing the WebView will be handled in `onProgressChanged()`. + nestedScrollWebView.setVisibility(View.VISIBLE); + } else { // The system is in night mode. + // Turn on algorithmic darkening. + WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.getSettings(), true); + } + } + } else if ((Build.VERSION.SDK_INT < 33) && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { // The device is running API < 33 and the WebView supports force dark. // Set the WebView theme. A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant. if (webViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected. // Turn off the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); // Make the WebView visible. The WebView was created invisible in `webview_framelayout` to prevent a white background splash in night mode. @@ -5023,6 +5147,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.setVisibility(View.VISIBLE); } else if (webViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected. // Turn on the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); } else { // The system default theme is selected. // Get the current system theme status. @@ -5031,6 +5156,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the WebView theme according to the current system theme status. if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { // The system is in day mode. // Turn off the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); // Make the WebView visible. The WebView was created invisible in `webview_framelayout` to prevent a white background splash in night mode. @@ -5038,6 +5164,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.setVisibility(View.VISIBLE); } else { // The system is in night mode. // Turn on the WebView dark mode. + //noinspection deprecation WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); } } @@ -5195,7 +5322,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Calculate the Y change. float motionY = motionEvent2.getY() - motionEvent1.getY(); - // Scroll the app bar if the change is greater than 100 pixels. + // Scroll the app bar if the change is greater than 50 pixels. if (motionY > 50) { // Animate the bottom app bar onto the screen. objectAnimator = ObjectAnimator.ofFloat(appBarLayout, "translationY", 0); @@ -6005,6 +6132,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } + // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, + // which links to `/data/data/com.stoutner.privacybrowser.standard`. + String privateDataDirectoryString = getApplicationInfo().dataDir; + // Clear the cache, history, and logcat if Incognito Mode is enabled. if (incognitoModeEnabled) { // Clear the cache. `true` includes disk files. @@ -6015,16 +6146,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Manually delete cache folders. try { - // Get the application's private data directory, which will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, - // which links to `/data/data/com.stoutner.privacybrowser.standard`. - String privateDataDirectoryString = getApplicationInfo().dataDir; - // Delete the main cache directory. Runtime.getRuntime().exec("rm -rf " + privateDataDirectoryString + "/cache"); - - // Delete the secondary `Service Worker` cache directory. - // A `String[]` must be used because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise. - Runtime.getRuntime().exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"}); } catch (IOException exception) { // Do nothing if an error is thrown. } @@ -6038,6 +6161,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } + // Clear the `Service Worker` directory. + try { + // A `String[]` must be used because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise. + Runtime.getRuntime().exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Default/Service Worker/"}); + } catch (IOException exception) { + // Do nothing. + } + // Get the current page position. int currentPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId());