From 0488649384ddea89d768c1fc1cc5fb71f8af6528 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Thu, 25 Jun 2020 13:40:58 -0700 Subject: [PATCH] Use WebView's new built-in dark theme. https://redmine.stoutner.com/issues/366 --- .idea/dictionaries/soren.xml | 1 + .../activities/DomainsActivity.java | 6 +- .../activities/MainWebViewActivity.java | 239 ++++++------ .../adapters/WebViewPagerAdapter.java | 3 +- .../fragments/DomainSettingsFragment.java | 345 +++++++++--------- .../fragments/SettingsFragment.java | 95 ++++- .../helpers/DomainsDatabaseHelper.java | 36 +- .../helpers/ImportExportDatabaseHelper.java | 170 +++++---- .../views/NestedScrollWebView.java | 32 +- ...led_day.xml => webview_dark_theme_day.xml} | 0 ...night.xml => webview_dark_theme_night.xml} | 0 ...ed_day.xml => webview_light_theme_day.xml} | 0 ...ight.xml => webview_light_theme_night.xml} | 0 .../res/layout/domain_settings_fragment.xml | 9 +- .../main/res/layout/webview_framelayout.xml | 8 +- .../main/res/menu/webview_options_menu.xml | 4 +- app/src/main/res/values-de/strings.xml | 6 - app/src/main/res/values-es/strings.xml | 6 - app/src/main/res/values-fr/strings.xml | 6 - app/src/main/res/values-it/strings.xml | 6 - app/src/main/res/values-night-v23/styles.xml | 1 - app/src/main/res/values-night-v27/styles.xml | 1 - app/src/main/res/values-night/styles.xml | 1 - app/src/main/res/values-ru/strings.xml | 6 - app/src/main/res/values-tr/strings.xml | 6 - app/src/main/res/values-v23/styles.xml | 1 - app/src/main/res/values-v27/styles.xml | 1 - app/src/main/res/values/attrs.xml | 1 - app/src/main/res/values/strings.xml | 8 +- app/src/main/res/values/styles.xml | 1 - app/src/main/res/xml/preferences.xml | 3 +- 31 files changed, 511 insertions(+), 491 deletions(-) rename app/src/main/res/drawable/{webview_theme_disabled_day.xml => webview_dark_theme_day.xml} (100%) rename app/src/main/res/drawable/{webview_theme_disabled_night.xml => webview_dark_theme_night.xml} (100%) rename app/src/main/res/drawable/{webview_theme_enabled_day.xml => webview_light_theme_day.xml} (100%) rename app/src/main/res/drawable/{webview_theme_enabled_night.xml => webview_light_theme_night.xml} (100%) diff --git a/.idea/dictionaries/soren.xml b/.idea/dictionaries/soren.xml index 1cefe928..db533740 100644 --- a/.idea/dictionaries/soren.xml +++ b/.idea/dictionaries/soren.xml @@ -108,6 +108,7 @@ materialdesignicons mimetype mitm + mojeek mozilla navigationview nestedscroll diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java index 6c07a121..6baf5f6e 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java @@ -707,7 +707,7 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo Spinner fontSizeSpinner = view.findViewById(R.id.font_size_spinner); EditText customFontSizeEditText = view.findViewById(R.id.custom_font_size_edittext); Spinner swipeToRefreshSpinner = view.findViewById(R.id.swipe_to_refresh_spinner); - Spinner nightModeSpinner = view.findViewById(R.id.night_mode_spinner); + Spinner webViewThemeSpinner = view.findViewById(R.id.webview_theme_spinner); Spinner wideViewportSpinner = view.findViewById(R.id.wide_viewport_spinner); Spinner displayWebpageImagesSpinner = view.findViewById(R.id.display_webpage_images_spinner); Switch pinnedSslCertificateSwitch = view.findViewById(R.id.pinned_ssl_certificate_switch); @@ -732,7 +732,7 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo int userAgentSwitchPosition = userAgentSpinner.getSelectedItemPosition(); int fontSizeSwitchPosition = fontSizeSpinner.getSelectedItemPosition(); int swipeToRefreshInt = swipeToRefreshSpinner.getSelectedItemPosition(); - int nightModeInt = nightModeSpinner.getSelectedItemPosition(); + int webViewThemeInt = webViewThemeSpinner.getSelectedItemPosition(); int wideViewportInt = wideViewportSpinner.getSelectedItemPosition(); int displayWebpageImagesInt = displayWebpageImagesSpinner.getSelectedItemPosition(); boolean pinnedSslCertificate = pinnedSslCertificateSwitch.isChecked(); @@ -772,7 +772,7 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo // Save the domain settings. domainsDatabaseHelper.updateDomain(DomainsActivity.currentDomainDatabaseId, domainNameString, javaScript, firstPartyCookies, thirdPartyCookies, domStorage, formData, easyList, easyPrivacy, - fanboysAnnoyance, fanboysSocialBlocking, ultraList, ultraPrivacy, blockAllThirdPartyRequests, userAgentName, fontSizeInt, swipeToRefreshInt, nightModeInt, wideViewportInt, + fanboysAnnoyance, fanboysSocialBlocking, ultraList, ultraPrivacy, blockAllThirdPartyRequests, userAgentName, fontSizeInt, swipeToRefreshInt, webViewThemeInt, wideViewportInt, displayWebpageImagesInt, pinnedSslCertificate, pinnedIpAddress); // Update the pinned SSL certificate if a new one is checked. 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 be28dd88..c130a267 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -668,6 +668,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook MenuItem toggleSaveFormDataMenuItem = menu.findItem(R.id.toggle_save_form_data); // Form data can be removed once the minimum API >= 26. MenuItem clearFormDataMenuItem = menu.findItem(R.id.clear_form_data); // Form data can be removed once the minimum API >= 26. MenuItem refreshMenuItem = menu.findItem(R.id.refresh); + MenuItem darkWebViewMenuItem = menu.findItem(R.id.dark_webview); MenuItem adConsentMenuItem = menu.findItem(R.id.ad_consent); // Only display third-party cookies if API >= 21 @@ -680,6 +681,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Disable the clear form data menu item if the API >= 26 so that the status of the main Clear Data is calculated correctly. clearFormDataMenuItem.setEnabled(Build.VERSION.SDK_INT < 26); + // Only display the dark WebView menu item if API >= 21. + darkWebViewMenuItem.setVisible(Build.VERSION.SDK_INT >= 21); + // Only show Ad Consent if this is the free flavor. adConsentMenuItem.setVisible(BuildConfig.FLAVOR.contentEquals("free")); @@ -751,7 +755,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook MenuItem swipeToRefreshMenuItem = menu.findItem(R.id.swipe_to_refresh); MenuItem wideViewportMenuItem = menu.findItem(R.id.wide_viewport); MenuItem displayImagesMenuItem = menu.findItem(R.id.display_images); - MenuItem nightModeMenuItem = menu.findItem(R.id.night_mode); + MenuItem darkWebViewMenuItem = menu.findItem(R.id.dark_webview); // Get a handle for the cookie manager. CookieManager cookieManager = CookieManager.getInstance(); @@ -788,7 +792,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook swipeToRefreshMenuItem.setChecked(currentWebView.getSwipeToRefresh()); wideViewportMenuItem.setChecked(currentWebView.getSettings().getUseWideViewPort()); displayImagesMenuItem.setChecked(currentWebView.getSettings().getLoadsImagesAutomatically()); - nightModeMenuItem.setChecked(currentWebView.getNightMode()); // Initialize the display names for the blocklists with the number of blocked requests. blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + currentWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); @@ -811,6 +814,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Enable DOM Storage if JavaScript is enabled. domStorageMenuItem.setEnabled(currentWebView.getSettings().getJavaScriptEnabled()); + + // Set the checkbox status for dark WebView if the WebView supports it. + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + darkWebViewMenuItem.setChecked(WebSettingsCompat.getForceDark(currentWebView.getSettings()) == WebSettingsCompat.FORCE_DARK_ON); + } } // Set the checked status of the first party cookies menu item. @@ -1557,28 +1565,19 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Consume the event. return true; - case R.id.night_mode: - // Toggle night mode. - currentWebView.setNightMode(!currentWebView.getNightMode()); - - // Enable or disable JavaScript according to night mode, the global preference, and any domain settings. - if (currentWebView.getNightMode()) { // Night mode is enabled, which requires JavaScript. - // Enable JavaScript. - currentWebView.getSettings().setJavaScriptEnabled(true); - } else if (currentWebView.getDomainSettingsApplied()) { // Night mode is disabled and domain settings are applied. Set JavaScript according to the domain settings. - // Apply the JavaScript preference that was stored the last time domain settings were loaded. - currentWebView.getSettings().setJavaScriptEnabled(currentWebView.getDomainSettingsJavaScriptEnabled()); - } else { // Night mode is disabled and domain settings are not applied. Set JavaScript according to the global preference. - // Apply the JavaScript preference. - currentWebView.getSettings().setJavaScriptEnabled(sharedPreferences.getBoolean("javascript", false)); + case R.id.dark_webview: + // Check to see if dark WebView is supported by this WebView. + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + // Toggle the dark WebView setting. + if (WebSettingsCompat.getForceDark(currentWebView.getSettings()) == WebSettingsCompat.FORCE_DARK_ON) { // Dark WebView is currently enabled. + // Turn off dark WebView. + WebSettingsCompat.setForceDark(currentWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); + } else { // Dark WebView is currently disabled. + // turn on dark WebView. + WebSettingsCompat.setForceDark(currentWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); + } } - // Update the privacy icons. - updatePrivacyIcons(false); - - // Reload the website. - currentWebView.reload(); - // Consume the event. return true; @@ -3877,7 +3876,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the settings from the cursor. nestedScrollWebView.setDomainSettingsDatabaseId(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID))); - nestedScrollWebView.setDomainSettingsJavaScriptEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1); + nestedScrollWebView.getSettings().setJavaScriptEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1); nestedScrollWebView.setAcceptFirstPartyCookies(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1); boolean domainThirdPartyCookiesEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1); nestedScrollWebView.getSettings().setDomStorageEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1); @@ -3899,7 +3898,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook String userAgentName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT)); int fontSize = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE)); int swipeToRefreshInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH)); - int nightModeInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE)); + int webViewThemeInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.WEBVIEW_THEME)); int wideViewportInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT)); int displayWebpageImagesInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES)); boolean pinnedSslCertificate = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE)) == 1); @@ -3930,6 +3929,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook pinnedSslEndDate = new Date(currentDomainSettingsCursor.getLong(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE))); } + // Close the current host domain settings cursor. + currentDomainSettingsCursor.close(); + // If there is a pinned SSL certificate, store it in the WebView. if (pinnedSslCertificate) { nestedScrollWebView.setPinnedSslCertificate(pinnedSslIssuedToCName, pinnedSslIssuedToOName, pinnedSslIssuedToUName, pinnedSslIssuedByCName, pinnedSslIssuedByOName, pinnedSslIssuedByUName, @@ -3941,37 +3943,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.setPinnedIpAddresses(pinnedHostIpAddresses); } - // Set night mode according to the night mode int. - switch (nightModeInt) { - case DomainsDatabaseHelper.SYSTEM_DEFAULT: - // Set night mode according to the current default. - nestedScrollWebView.setNightMode(sharedPreferences.getBoolean("night_mode", false)); - break; - - case DomainsDatabaseHelper.ENABLED: - // Enable night mode. - nestedScrollWebView.setNightMode(true); - break; - - case DomainsDatabaseHelper.DISABLED: - // Disable night mode. - nestedScrollWebView.setNightMode(false); - break; - } - - // Enable JavaScript if night mode is enabled. - if (nestedScrollWebView.getNightMode()) { - // Enable JavaScript. - nestedScrollWebView.getSettings().setJavaScriptEnabled(true); - } else { - // Set JavaScript according to the domain settings. - nestedScrollWebView.getSettings().setJavaScriptEnabled(nestedScrollWebView.getDomainSettingsJavaScriptEnabled()); - } - - // Close the current host domain settings cursor. - currentDomainSettingsCursor.close(); - - // Apply the domain settings. + // Apply the cookie domain settings. cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptFirstPartyCookies()); // Set third-party cookies status if API >= 21. @@ -4075,6 +4047,36 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook swipeRefreshLayout.setEnabled(false); } + // Check to see if WebView themes are supported. + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + // Set the WebView theme. + switch (webViewThemeInt) { + case DomainsDatabaseHelper.SYSTEM_DEFAULT: + // // Ge the current system theme status. + int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + + // Set the WebView theme according to the current system theme status. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { // The system is in night mode. + // Turn on the WebView dark mode. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); + } else { // The system is in day mode. + // Turn off the WebView dark mode. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); + } + break; + + case DomainsDatabaseHelper.LIGHT_THEME: + // Turn off the WebView dark mode. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); + break; + + case DomainsDatabaseHelper.DARK_THEME: + // Turn on the WebView dark mode. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); + break; + } + } + // Set the viewport. switch (wideViewportInt) { case DomainsDatabaseHelper.SYSTEM_DEFAULT: @@ -4116,7 +4118,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } else { // The new URL does not have custom domain settings. Load the defaults. // Store the values from the shared preferences. - boolean defaultJavaScriptEnabled = sharedPreferences.getBoolean("javascript", false); + nestedScrollWebView.getSettings().setJavaScriptEnabled(sharedPreferences.getBoolean("javascript", false)); nestedScrollWebView.setAcceptFirstPartyCookies(sharedPreferences.getBoolean("first_party_cookies", false)); boolean defaultThirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies", false); nestedScrollWebView.getSettings().setDomStorageEnabled(sharedPreferences.getBoolean("dom_storage", false)); @@ -4128,16 +4130,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRALIST, sharedPreferences.getBoolean("ultralist", true)); nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRAPRIVACY, sharedPreferences.getBoolean("ultraprivacy", true)); nestedScrollWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS, sharedPreferences.getBoolean("block_all_third_party_requests", false)); - nestedScrollWebView.setNightMode(sharedPreferences.getBoolean("night_mode", false)); - - // Enable JavaScript if night mode is enabled. - if (nestedScrollWebView.getNightMode()) { - // Enable JavaScript. - nestedScrollWebView.getSettings().setJavaScriptEnabled(true); - } else { - // Set JavaScript according to the domain settings. - nestedScrollWebView.getSettings().setJavaScriptEnabled(defaultJavaScriptEnabled); - } + String webViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value)); // Apply the default first-party cookie setting. cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptFirstPartyCookies()); @@ -4201,6 +4194,33 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.getSettings().setUserAgentString(userAgentDataArray[userAgentArrayPosition]); } + // 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)) { + // 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. + 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. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); + } 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 WebView theme according to the current system theme status. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { // The system is in night mode. + // Turn on the WebView dark mode. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); + } else { // The system is in day mode. + // Turn off the WebView dark mode. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); + } + } + } + // Set the viewport. nestedScrollWebView.getSettings().setUseWideViewPort(wideViewport); @@ -4987,6 +5007,39 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @Override public void initializeWebView(NestedScrollWebView nestedScrollWebView, int pageNumber, ProgressBar progressBar, String url) { + // Get a handle for the shared preferences. + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + + // Get the WebView theme. + String webViewTheme = sharedPreferences.getString("webview_theme", 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)) { + // 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. + 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. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); + } 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 WebView theme according to the current system theme status. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { // The system is in night mode. + // Turn on the WebView dark mode. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); + } else { // The system is in day mode. + // Turn off the WebView dark mode. + WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_OFF); + } + } + } + // Get a handle for the app compat delegate. AppCompatDelegate appCompatDelegate = getDelegate(); @@ -5015,9 +5068,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Remove the lint warning below that the input method manager might be null. assert inputMethodManager != null; - // Get a handle for the shared preferences. - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - // Initialize the favorite icon. nestedScrollWebView.initializeFavoriteIcon(); @@ -5234,46 +5284,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook }); } - // TODO. - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { - WebSettingsCompat.setForceDark(nestedScrollWebView.getSettings(), WebSettingsCompat.FORCE_DARK_AUTO); - } - // Set the web chrome client. nestedScrollWebView.setWebChromeClient(new WebChromeClient() { // Update the progress bar when a page is loading. @Override public void onProgressChanged(WebView view, int progress) { - // Inject the night mode CSS if night mode is enabled. - if (nestedScrollWebView.getNightMode()) { // Night mode is enabled. - // `background-color: #212121` sets the background to be dark gray. `color: #BDBDBD` sets the text color to be light gray. `box-shadow: none` removes a lower underline on links - // used by WordPress. `text-decoration: none` removes all text underlines. `text-shadow: none` removes text shadows, which usually have a hard coded color. - // `border: none` removes all borders, which can also be used to underline text. `a {color: #1565C0}` sets links to be a dark blue. - // `::selection {background: #0D47A1}' sets the text selection highlight color to be a dark blue. `!important` takes precedent over any existing sub-settings. - nestedScrollWebView.evaluateJavascript("(function() {var parent = document.getElementsByTagName('head').item(0); var style = document.createElement('style'); style.type = 'text/css'; " + - "style.innerHTML = '* {background-color: #212121 !important; color: #BDBDBD !important; box-shadow: none !important; text-decoration: none !important;" + - "text-shadow: none !important; border: none !important;} a {color: #1565C0 !important;} ::selection {background: #0D47A1 !important;}'; parent.appendChild(style)})()", value -> { - // Initialize a handler to display `mainWebView`. - Handler displayWebViewHandler = new Handler(); - - // Setup a runnable to display `mainWebView` after a delay to allow the CSS to be applied. - Runnable displayWebViewRunnable = () -> { - // Only display `mainWebView` if the progress bar is gone. This prevents the display of the `WebView` while it is still loading. - if (progressBar.getVisibility() == View.GONE) { - nestedScrollWebView.setVisibility(View.VISIBLE); - } - }; - - // Display the WebView after 500 milliseconds. - displayWebViewHandler.postDelayed(displayWebViewRunnable, 500); - }); - } else { // Night mode is disabled. - // Display the nested scroll WebView if night mode is disabled. - // Because of a race condition between `applyDomainSettings` and `onPageStarted`, - // when night mode is set by domain settings the WebView may be hidden even if night mode is not currently enabled. - nestedScrollWebView.setVisibility(View.VISIBLE); - } - // Update the progress bar. progressBar.setProgress(progress); @@ -5288,6 +5303,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook //Stop the swipe to refresh indicator if it is running swipeRefreshLayout.setRefreshing(false); } + + // If this is a new tab, the current WebView would have been created invisible in `webview_framelayout` to prevent a white background splash in night mode. + if (progress >= 50) { + // Make the current WebView visible. + currentWebView.setVisibility(View.VISIBLE); + } } // Set the favorite icon when it changes. @@ -5504,7 +5525,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Apply the domain settings for the new URL. This doesn't do anything if the domain has not changed. applyDomainSettings(nestedScrollWebView, url, true, false); - // Manually load the URL. The changing of the user agent will cause WebView to reload the previous URL. + // Load the URL. By using `loadUrl()`, instead of `loadUrlFromBase()`, the Referer header will never be sent. nestedScrollWebView.loadUrl(url, customHeaders); // Returning true indicates that Privacy Browser is manually handling the loading of the URL. @@ -5966,14 +5987,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Reset the requests counters. nestedScrollWebView.resetRequestsCounters(); - // TODO. Make the background of a new tab match the theme. - // If night mode is enabled, hide `mainWebView` until after the night mode CSS is applied. - if (nestedScrollWebView.getNightMode()) { - nestedScrollWebView.setVisibility(View.INVISIBLE); - } else { - nestedScrollWebView.setVisibility(View.VISIBLE); - } - // Hide the keyboard. inputMethodManager.hideSoftInputFromWindow(nestedScrollWebView.getWindowToken(), 0); diff --git a/app/src/main/java/com/stoutner/privacybrowser/adapters/WebViewPagerAdapter.java b/app/src/main/java/com/stoutner/privacybrowser/adapters/WebViewPagerAdapter.java index 5947df44..535512a5 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/adapters/WebViewPagerAdapter.java +++ b/app/src/main/java/com/stoutner/privacybrowser/adapters/WebViewPagerAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright © 2019 Soren Stoutner . + * Copyright © 2019-2020 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -59,6 +59,7 @@ public class WebViewPagerAdapter extends FragmentPagerAdapter { } @Override + @NonNull public Fragment getItem(int pageNumber) { // Get the fragment for a particular page. Page numbers are 0 indexed. return webViewFragmentsList.get(pageNumber); diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java b/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java index 10fb6637..1588ad3c 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java @@ -104,7 +104,7 @@ public class DomainSettingsFragment extends Fragment { String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value)); String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value)); boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true); - boolean defaultNightMode = sharedPreferences.getBoolean("night_mode", false); + String defaultWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value)); boolean defaultWideViewport = sharedPreferences.getBoolean("wide_viewport", true); boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true); @@ -144,9 +144,9 @@ public class DomainSettingsFragment extends Fragment { ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview); Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner); TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview); - ImageView nightModeImageView = domainSettingsView.findViewById(R.id.night_mode_imageview); - Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.night_mode_spinner); - TextView nightModeTextView = domainSettingsView.findViewById(R.id.night_mode_textview); + ImageView webViewThemeImageView = domainSettingsView.findViewById(R.id.webview_theme_imageview); + Spinner webViewThemeSpinner = domainSettingsView.findViewById(R.id.webview_theme_spinner); + TextView webViewThemeTextView = domainSettingsView.findViewById(R.id.webview_theme_textview); ImageView wideViewportImageView = domainSettingsView.findViewById(R.id.wide_viewport_imageview); Spinner wideViewportSpinner = domainSettingsView.findViewById(R.id.wide_viewport_spinner); TextView wideViewportTextView = domainSettingsView.findViewById(R.id.wide_viewport_textview); @@ -220,7 +220,7 @@ public class DomainSettingsFragment extends Fragment { String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT)); int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE)); int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH)); - int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE)); + int webViewThemeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WEBVIEW_THEME)); int wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT)); int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES)); int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE)); @@ -250,7 +250,7 @@ public class DomainSettingsFragment extends Fragment { ArrayAdapter translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item); ArrayAdapter fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.font_size_array, R.layout.spinner_item); ArrayAdapter swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item); - ArrayAdapter nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item); + ArrayAdapter webViewThemeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.webview_theme_array, R.layout.spinner_item); ArrayAdapter wideViewportArrayAdapter = ArrayAdapter.createFromResource(context, R.array.wide_viewport_array, R.layout.spinner_item); ArrayAdapter displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item); @@ -258,7 +258,7 @@ public class DomainSettingsFragment extends Fragment { translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items); fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items); swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items); - nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items); + webViewThemeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items); wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items); displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items); @@ -266,7 +266,7 @@ public class DomainSettingsFragment extends Fragment { userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter); fontSizeSpinner.setAdapter(fontSizeArrayAdapter); swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter); - nightModeSpinner.setAdapter(nightModeArrayAdapter); + webViewThemeSpinner.setAdapter(webViewThemeArrayAdapter); wideViewportSpinner.setAdapter(wideViewportArrayAdapter); displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter); @@ -365,28 +365,13 @@ public class DomainSettingsFragment extends Fragment { } }); - // Create a boolean to track if night mode is enabled. - boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.ENABLED) || ((nightModeInt == DomainsDatabaseHelper.SYSTEM_DEFAULT) && defaultNightMode); - - // Disable the JavaScript switch if night mode is enabled. - if (nightModeEnabled) { - javaScriptSwitch.setEnabled(false); - } else { - javaScriptSwitch.setEnabled(true); - } - - // Set the JavaScript icon. - if ((javaScriptInt == 1) || nightModeEnabled) { - javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled)); - } else { - javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode)); - } - // Set the JavaScript switch status. if (javaScriptInt == 1) { // JavaScript is enabled. javaScriptSwitch.setChecked(true); + javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled)); } else { // JavaScript is disabled. javaScriptSwitch.setChecked(false); + javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode)); } // Set the first-party cookies status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. @@ -450,7 +435,7 @@ public class DomainSettingsFragment extends Fragment { } // Only enable DOM storage if JavaScript is enabled. - if ((javaScriptInt == 1) || nightModeEnabled) { // JavaScript is enabled. + if (javaScriptInt == 1) { // JavaScript is enabled. // Enable the DOM storage `Switch`. domStorageSwitch.setEnabled(true); @@ -488,19 +473,23 @@ public class DomainSettingsFragment extends Fragment { } } - // Set the form data status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. Form data can be removed once the minimum API >= 26. + // Set the form data visibility. Form data can be removed once the minimum API >= 26. if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android. - // Hide the form data switch. + // Hide the form data image view and switch. + formDataImageView.setVisibility(View.GONE); formDataSwitch.setVisibility(View.GONE); } else { // Form data should be displayed because this is an older version of Android. if (formDataInt == 1) { // Form data is on. + // Turn the form data switch on. formDataSwitch.setChecked(true); + + // Set the form data icon. formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled)); } else { // Form data is off. // Turn the form data switch to off. formDataSwitch.setChecked(false); - // Set the icon according to the theme. + // Set the icon according to the theme. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_night)); } else { @@ -809,7 +798,7 @@ public class DomainSettingsFragment extends Fragment { fontSizeSpinner.performClick(); }); - // Display the swipe to refresh selection in the spinner. + // Select the swipe to refresh selection in the spinner. swipeToRefreshSpinner.setSelection(swipeToRefreshInt); // Set the swipe to refresh text. @@ -872,71 +861,121 @@ public class DomainSettingsFragment extends Fragment { swipeToRefreshSpinner.performClick(); }); - // Display the night mode in the spinner. - nightModeSpinner.setSelection(nightModeInt); - - // Set the default night mode text. - if (defaultNightMode) { - nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED)); - } else { - nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED)); + // Get the WebView theme string arrays. + String[] webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array); + String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values); + + // Define an app WebView theme entry number. + int appWebViewThemeEntryNumber; + + // Get the WebView theme entry number that matches the current WebView theme. A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant. + if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected. + // Store the default WebView theme entry number. + appWebViewThemeEntryNumber = 1; + } else if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected. + // Store the default WebView theme entry number. + appWebViewThemeEntryNumber = 2; + } else { // The system default theme is selected. + // Store the default WebView theme entry number. + appWebViewThemeEntryNumber = 0; } - // Set the night mode icon and TextView settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. - switch (nightModeInt) { - case DomainsDatabaseHelper.SYSTEM_DEFAULT: - if (defaultNightMode) { // Night mode enabled by default. - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_enabled_night)); - } else { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_enabled_day)); + // Set the WebView theme visibility. + if (Build.VERSION.SDK_INT < 21) { // The WebView theme cannot be set on API 19. + // Get a handle for the webView theme linear layout. + LinearLayout webViewThemeLinearLayout = domainSettingsView.findViewById(R.id.webview_theme_linearlayout); + + // Hide the WebView theme linear layout. + webViewThemeLinearLayout.setVisibility(View.GONE); + } else { // The WebView theme can be set on API >= 21. + // Select the WebView theme in the spinner. + webViewThemeSpinner.setSelection(webViewThemeInt); + + // Set the WebView theme text. + if (appWebViewThemeEntryNumber == DomainsDatabaseHelper.SYSTEM_DEFAULT) { // The app WebView theme is system default. + // Set the text according to the current UI theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.LIGHT_THEME]); + } else { + webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.DARK_THEME]); + } + } else { // The app WebView theme is not system default. + // Set the text according to the app WebView theme. + webViewThemeTextView.setText(webViewThemeStringArray[appWebViewThemeEntryNumber]); + } + + // Set the WebView theme icon and text visibility. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. + switch (webViewThemeInt) { + case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The domain WebView theme is system default. + // Set the icon according to the app WebView theme. + switch (appWebViewThemeEntryNumber) { + case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + // Set the light mode icon. + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_day)); + } else { + // Set the dark theme icon. + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_night)); + } + break; + + case DomainsDatabaseHelper.LIGHT_THEME: // the default WebView theme is light. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_day)); + } else { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_night)); + } + break; + + case DomainsDatabaseHelper.DARK_THEME: // the default WebView theme is dark. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_day)); + } else { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_night)); + } + break; } - } else { // Night mode disabled by default. - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_disabled_night)); + + // Show the WebView theme text view. + webViewThemeTextView.setVisibility(View.VISIBLE); + break; + + case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_day)); } else { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_disabled_day)); + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_night)); } - } - // Show night mode TextView. - nightModeTextView.setVisibility(View.VISIBLE); - break; - - case DomainsDatabaseHelper.ENABLED: - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_enabled_night)); - } else { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_enabled_day)); - } + // Hide the WebView theme text view. + webViewThemeTextView.setVisibility(View.GONE); + break; - // Hide the night mode TextView. - nightModeTextView.setVisibility(View.GONE); - break; + case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_day)); + } else { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_night)); + } - case DomainsDatabaseHelper.DISABLED: - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_disabled_night)); - } else { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_disabled_day)); - } + // Hide the WebView theme text view. + webViewThemeTextView.setVisibility(View.GONE); + break; + } - // Hide the night mode TextView. - nightModeTextView.setVisibility(View.GONE); - break; + // Open the WebView theme spinner when the text view is clicked. + webViewThemeTextView.setOnClickListener((View v) -> { + // Open the WebView theme spinner. + webViewThemeSpinner.performClick(); + }); } - // Open the night mode spinner when the TextView is clicked. - nightModeTextView.setOnClickListener((View v) -> { - // Open the night mode spinner. - nightModeSpinner.performClick(); - }); - - // Display the wide viewport in the spinner. + // Select the wide viewport in the spinner. wideViewportSpinner.setSelection(wideViewportInt); // Set the default wide viewport text. @@ -1771,112 +1810,72 @@ public class DomainSettingsFragment extends Fragment { } }); - // Set the night mode spinner listener. - nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + // Set the WebView theme spinner listener. + webViewThemeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { - // Update the icon and the visibility of `nightModeTextView`. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. + // Update the icon and the visibility of the WebView theme text view. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. switch (position) { - case DomainsDatabaseHelper.SYSTEM_DEFAULT: - if (defaultNightMode) { // Night mode enabled by default. - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_enabled_night)); - } else { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_enabled_day)); - } - } else { // Night mode disabled by default. - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_disabled_night)); - } else { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_disabled_day)); - } - } + case DomainsDatabaseHelper.SYSTEM_DEFAULT: // the domain WebView theme is system default. + // Set the icon according to the app WebView theme. + switch (appWebViewThemeEntryNumber) { + case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + // Set the light mode icon. + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_day)); + } else { + // Set the dark theme icon. + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_night)); + } + break; - // Show the night mode TextView. - nightModeTextView.setVisibility(View.VISIBLE); - break; + case DomainsDatabaseHelper.LIGHT_THEME: // The default WebView theme is light. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_day)); + } else { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_night)); + } + break; - case DomainsDatabaseHelper.ENABLED: - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_enabled_night)); - } else { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_enabled_day)); + case DomainsDatabaseHelper.DARK_THEME: // The default WebView theme is dark. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_day)); + } else { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_night)); + } + break; } - // Hide `nightModeTextView`. - nightModeTextView.setVisibility(View.GONE); + // Show the WebView theme text view. + webViewThemeTextView.setVisibility(View.VISIBLE); break; - case DomainsDatabaseHelper.DISABLED: - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_disabled_night)); + case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_day)); } else { - nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_theme_disabled_day)); + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_light_theme_night)); } - // Hide `nightModeTextView`. - nightModeTextView.setVisibility(View.GONE); + // Hide the WebView theme text view. + webViewThemeTextView.setVisibility(View.GONE); break; - } - - // Create a boolean to store the current night mode setting. - boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.ENABLED) || ((position == DomainsDatabaseHelper.SYSTEM_DEFAULT) && defaultNightMode); - - // Disable the JavaScript switch if night mode is enabled. - if (currentNightModeEnabled) { - javaScriptSwitch.setEnabled(false); - } else { - javaScriptSwitch.setEnabled(true); - } - - // Update the JavaScript icon. - if ((javaScriptInt == 1) || currentNightModeEnabled) { - javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled)); - } else { - javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode)); - } - - // Update the DOM storage status. - if ((javaScriptInt == 1) || currentNightModeEnabled) { // JavaScript is enabled. - // Enable the DOM storage `Switch`. - domStorageSwitch.setEnabled(true); - - // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. - if (domStorageInt == 1) { // Both JavaScript and DOM storage are enabled. - domStorageSwitch.setChecked(true); - domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled)); - } else { // JavaScript is enabled but DOM storage is disabled. - // Set the DOM storage switch to off. - domStorageSwitch.setChecked(false); - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_night)); + case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_day)); } else { - domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_day)); + webViewThemeImageView.setImageDrawable(resources.getDrawable(R.drawable.webview_dark_theme_night)); } - } - } else { // JavaScript is disabled. - // Disable the DOM storage `Switch`. - domStorageSwitch.setEnabled(false); - - // Set the checked status of DOM storage. - if (domStorageInt == 1) { // DOM storage is enabled but JavaScript is disabled. - domStorageSwitch.setChecked(true); - } else { // Both JavaScript and DOM storage are disabled. - domStorageSwitch.setChecked(false); - } - // Set the icon according to the theme. - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_night)); - } else { - domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_day)); - } + // Hide the WebView theme text view. + webViewThemeTextView.setVisibility(View.GONE); + break; } } diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java b/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java index 6130ece8..eb70ef25 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java @@ -361,7 +361,25 @@ public class SettingsFragment extends PreferenceFragmentCompat { String[] webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries); String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values); - // Hide the WebView theme preference if the API < 21. + // Get the current WebView theme. + String currentWebViewTheme = savedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value)); + + // Define a WebView theme entry number. + int webViewThemeEntryNumber; + + // Get the WebView theme entry number that matches the current WebView theme. A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant. + if (currentWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected. + // Store the WebView theme entry number. + webViewThemeEntryNumber = 1; + } else if (currentWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected. + // Store the WebView theme entry number. + webViewThemeEntryNumber = 2; + } else { // The system default theme is selected. + // Store the WebView theme entry number. + webViewThemeEntryNumber = 0; + } + + // Set the visibility of the WebView theme preference. if (Build.VERSION.SDK_INT < 21) { // The device is running API 19. // Get a handle for the general category. PreferenceCategory generalCategory = findPreference("general"); @@ -372,24 +390,6 @@ public class SettingsFragment extends PreferenceFragmentCompat { // Remove the WebView theme preference. generalCategory.removePreference(webViewThemePreference); } else { // The device is running API >= 21 - // Get the current WebView theme. - String currentWebViewTheme = savedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value)); - - // Define a WebView theme entry number. - int webViewThemeEntryNumber; - - // Get the WebView theme entry number that matches the current WebView theme. A switch statement cannot be used because the theme entry values string array is not a compile time constant. - if (currentWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected. - // Store the WebView theme entry number. - webViewThemeEntryNumber = 1; - } else if (currentWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected. - // Store the WebView theme entry number. - webViewThemeEntryNumber = 2; - } else { // The system default theme is selected. - // Store the WebView theme entry number. - webViewThemeEntryNumber = 0; - } - // Set the current theme as the summary text for the preference. webViewThemePreference.setSummary(webViewThemeEntriesStringArray[webViewThemeEntryNumber]); } @@ -905,6 +905,35 @@ public class SettingsFragment extends PreferenceFragmentCompat { } } + // Set the WebView theme preference icon. + switch (webViewThemeEntryNumber) { + case 0: // The system default WebView theme is selected. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemePreference.setIcon(R.drawable.webview_light_theme_day); + } else { + webViewThemePreference.setIcon(R.drawable.webview_dark_theme_night); + } + break; + + case 1: // The light WebView theme is selected. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemePreference.setIcon(R.drawable.webview_light_theme_day); + } else { + webViewThemePreference.setIcon(R.drawable.webview_light_theme_night); + } + break; + + case 2: // The dark WebView theme is selected. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemePreference.setIcon(R.drawable.webview_dark_theme_day); + } else { + webViewThemePreference.setIcon(R.drawable.webview_dark_theme_night); + } + break; + } + // Set the wide viewport preference icon. if (savedPreferences.getBoolean("wide_viewport", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { @@ -1860,6 +1889,34 @@ public class SettingsFragment extends PreferenceFragmentCompat { newWebViewThemeEntryNumber = 0; } + // Update the icon. + switch (newWebViewThemeEntryNumber) { + case 0: // The system default WebView theme is selected. + // Set the icon according to the app theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemePreference.setIcon(R.drawable.webview_light_theme_day); + } else { + webViewThemePreference.setIcon(R.drawable.webview_dark_theme_night); + } + break; + + case 1: // The system default WebView theme is selected. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemePreference.setIcon(R.drawable.webview_light_theme_day); + } else { + webViewThemePreference.setIcon(R.drawable.webview_light_theme_night); + } + break; + + case 2: // The system default WebView theme is selected. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + webViewThemePreference.setIcon(R.drawable.webview_dark_theme_day); + } else { + webViewThemePreference.setIcon(R.drawable.webview_dark_theme_night); + } + break; + } + // Set the current theme as the summary text for the preference. webViewThemePreference.setSummary(webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]); break; diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java b/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java index 1e40f970..e58997c3 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.java @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2019 Soren Stoutner . + * Copyright © 2017-2020 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -28,7 +28,7 @@ import android.database.sqlite.SQLiteOpenHelper; import android.preference.PreferenceManager; public class DomainsDatabaseHelper extends SQLiteOpenHelper { - private static final int SCHEMA_VERSION = 11; + private static final int SCHEMA_VERSION = 12; static final String DOMAINS_DATABASE = "domains.db"; static final String DOMAINS_TABLE = "domains"; @@ -49,7 +49,7 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { public static final String USER_AGENT = "useragent"; public static final String FONT_SIZE = "fontsize"; public static final String SWIPE_TO_REFRESH = "swipetorefresh"; - public static final String NIGHT_MODE = "nightmode"; + public static final String WEBVIEW_THEME = "webview_theme"; public static final String WIDE_VIEWPORT = "wide_viewport"; public static final String DISPLAY_IMAGES = "displayimages"; public static final String PINNED_SSL_CERTIFICATE = "pinnedsslcertificate"; @@ -68,6 +68,8 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { public static final int SYSTEM_DEFAULT = 0; public static final int ENABLED = 1; public static final int DISABLED = 2; + public static final int LIGHT_THEME = 1; + public static final int DARK_THEME = 2; static final String CREATE_DOMAINS_TABLE = "CREATE TABLE " + DOMAINS_TABLE + " (" + _ID + " INTEGER PRIMARY KEY, " + @@ -87,7 +89,7 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { USER_AGENT + " TEXT, " + FONT_SIZE + " INTEGER, " + SWIPE_TO_REFRESH + " INTEGER, " + - NIGHT_MODE + " INTEGER, " + + WEBVIEW_THEME + " INTEGER, " + WIDE_VIEWPORT + " INTEGER, " + DISPLAY_IMAGES + " INTEGER, " + PINNED_SSL_CERTIFICATE + " BOOLEAN, " + @@ -142,8 +144,8 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { // Upgrade from schema version 3. case 3: - // Add the Night Mode column. - domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + NIGHT_MODE + " INTEGER"); + // Add the night mode column. + domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN nightmode INTEGER"); // Upgrade from schema version 4. case 4: @@ -192,12 +194,12 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { // Upgrade from schema version 5. case 5: - // Add the swipe to refresh column. + // Add the swipe to refresh column. This defaults to `0`, which is `System default`, so a separate step isn't needed to populate the column. domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SWIPE_TO_REFRESH + " INTEGER"); // Upgrade from schema version 6. case 6: - // Add the block all third-party requests column. + // Add the block all third-party requests column. This defaults to `0`, which is off, so a separate step isn't needed to populate the column. domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + BLOCK_ALL_THIRD_PARTY_REQUESTS + " BOOLEAN"); // Upgrade from schema version 7. @@ -210,13 +212,13 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { // Upgrade from schema version 8. case 8: - // Add the Pinned IP Addresses columns. + // Add the pinned IP addresses columns. These default to `0` and `""`, so a separate step isn't needed to populate the columns. domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + PINNED_IP_ADDRESSES + " BOOLEAN"); domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + IP_ADDRESSES + " TEXT"); // Upgrade from schema version 9. case 9: - // Add the Wide Viewport column. + // Add the wide viewport column. This defaults to `0`, which is `System default`, so a separate step isn't needed to populate the column. domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + WIDE_VIEWPORT + " INTEGER"); // Upgrade from schema version 10. @@ -226,6 +228,14 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { // Enable it for all existing rows. domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ULTRALIST + " = " + 1); + + // Upgrade from schema version 11. + case 11: + // Add the WebView theme column. This defaults to `0`, which is `System default`, so a separate step isn't needed to populate the column. + domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + WEBVIEW_THEME + " INTEGER"); + + // SQLite amazingly doesn't include an easy command to delete a column. + // Although a new table could be created and all the data copied to it, I think I will just leave the old night mode column. It will be wiped out the next time an import is run. } } @@ -323,7 +333,7 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { domainContentValues.put(USER_AGENT, "System default user agent"); domainContentValues.put(FONT_SIZE, 0); domainContentValues.put(SWIPE_TO_REFRESH, 0); - domainContentValues.put(NIGHT_MODE, 0); + domainContentValues.put(WEBVIEW_THEME, 0); domainContentValues.put(WIDE_VIEWPORT, 0); domainContentValues.put(DISPLAY_IMAGES, 0); @@ -353,7 +363,7 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { public void updateDomain(int databaseId, String domainName, boolean javaScript, boolean firstPartyCookies, boolean thirdPartyCookies, boolean domStorage, boolean formData, boolean easyList, boolean easyPrivacy, boolean fanboysAnnoyance, boolean fanboysSocialBlocking, boolean ultraList, boolean ultraPrivacy, boolean blockAllThirdPartyRequests, String userAgent, - int fontSize, int swipeToRefresh, int nightMode, int wideViewport, int displayImages, boolean pinnedSslCertificate, boolean pinnedIpAddresses) { + int fontSize, int swipeToRefresh, int webViewTheme, int wideViewport, int displayImages, boolean pinnedSslCertificate, boolean pinnedIpAddresses) { // Store the domain data in a `ContentValues`. ContentValues domainContentValues = new ContentValues(); @@ -375,7 +385,7 @@ public class DomainsDatabaseHelper extends SQLiteOpenHelper { domainContentValues.put(USER_AGENT, userAgent); domainContentValues.put(FONT_SIZE, fontSize); domainContentValues.put(SWIPE_TO_REFRESH, swipeToRefresh); - domainContentValues.put(NIGHT_MODE, nightMode); + domainContentValues.put(WEBVIEW_THEME, webViewTheme); domainContentValues.put(WIDE_VIEWPORT, wideViewport); domainContentValues.put(DISPLAY_IMAGES, displayImages); domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate); diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java b/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java index 6815258a..8ad6e15a 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java @@ -84,7 +84,7 @@ public class ImportExportDatabaseHelper { private static final String SCROLL_APP_BAR = "scroll_app_bar"; private static final String DISPLAY_ADDITIONAL_APP_BAR_ICONS = "display_additional_app_bar_icons"; private static final String APP_THEME = "app_theme"; - private static final String NIGHT_MODE = "night_mode"; + private static final String WEBVIEW_THEME = "webview_theme"; private static final String WIDE_VIEWPORT = "wide_viewport"; private static final String DISPLAY_WEBPAGE_IMAGES = "display_webpage_images"; @@ -105,6 +105,42 @@ public class ImportExportDatabaseHelper { // Create the export database domains table. exportDatabase.execSQL(DomainsDatabaseHelper.CREATE_DOMAINS_TABLE); + + // Create the export database bookmarks table. + exportDatabase.execSQL(BookmarksDatabaseHelper.CREATE_BOOKMARKS_TABLE); + + // Open the bookmarks database. The `0` specifies the database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`. + BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(context, null, null, 0); + + // Get a full bookmarks cursor. + Cursor bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarks(); + + // Move to the first bookmark. + bookmarksCursor.moveToFirst(); + + // Copy the data from the bookmarks cursor into the export database. + for (int i = 0; i < bookmarksCursor.getCount(); i++) { + // Extract the record from the cursor and store the data in a ContentValues. + ContentValues bookmarksContentValues = new ContentValues(); + bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_NAME, bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))); + bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_URL, bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL))); + bookmarksContentValues.put(BookmarksDatabaseHelper.PARENT_FOLDER, bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER))); + bookmarksContentValues.put(BookmarksDatabaseHelper.DISPLAY_ORDER, bookmarksCursor.getInt(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER))); + bookmarksContentValues.put(BookmarksDatabaseHelper.IS_FOLDER, bookmarksCursor.getInt(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.IS_FOLDER))); + bookmarksContentValues.put(BookmarksDatabaseHelper.FAVORITE_ICON, bookmarksCursor.getBlob(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON))); + + // Insert the record into the export database. + exportDatabase.insert(BookmarksDatabaseHelper.BOOKMARKS_TABLE, null, bookmarksContentValues); + + // Advance to the next record. + bookmarksCursor.moveToNext(); + } + + // Close the bookmarks database. + bookmarksCursor.close(); + bookmarksDatabaseHelper.close(); + + // Open the domains database. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`. DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0); @@ -134,7 +170,7 @@ public class ImportExportDatabaseHelper { domainsContentValues.put(DomainsDatabaseHelper.USER_AGENT, domainsCursor.getString(domainsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT))); domainsContentValues.put(DomainsDatabaseHelper.FONT_SIZE, domainsCursor.getInt(domainsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE))); domainsContentValues.put(DomainsDatabaseHelper.SWIPE_TO_REFRESH, domainsCursor.getInt(domainsCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH))); - domainsContentValues.put(DomainsDatabaseHelper.NIGHT_MODE, domainsCursor.getInt(domainsCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE))); + domainsContentValues.put(DomainsDatabaseHelper.WEBVIEW_THEME, domainsCursor.getInt(domainsCursor.getColumnIndex(DomainsDatabaseHelper.WEBVIEW_THEME))); domainsContentValues.put(DomainsDatabaseHelper.WIDE_VIEWPORT, domainsCursor.getInt(domainsCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT))); domainsContentValues.put(DomainsDatabaseHelper.DISPLAY_IMAGES, domainsCursor.getInt(domainsCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES))); domainsContentValues.put(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE, domainsCursor.getInt(domainsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE))); @@ -161,41 +197,6 @@ public class ImportExportDatabaseHelper { domainsDatabaseHelper.close(); - // Create the export database bookmarks table. - exportDatabase.execSQL(BookmarksDatabaseHelper.CREATE_BOOKMARKS_TABLE); - - // Open the bookmarks database. The `0` specifies the database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`. - BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(context, null, null, 0); - - // Get a full bookmarks cursor. - Cursor bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarks(); - - // Move to the first bookmark. - bookmarksCursor.moveToFirst(); - - // Copy the data from the bookmarks cursor into the export database. - for (int i = 0; i < bookmarksCursor.getCount(); i++) { - // Extract the record from the cursor and store the data in a ContentValues. - ContentValues bookmarksContentValues = new ContentValues(); - bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_NAME, bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))); - bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_URL, bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL))); - bookmarksContentValues.put(BookmarksDatabaseHelper.PARENT_FOLDER, bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER))); - bookmarksContentValues.put(BookmarksDatabaseHelper.DISPLAY_ORDER, bookmarksCursor.getInt(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER))); - bookmarksContentValues.put(BookmarksDatabaseHelper.IS_FOLDER, bookmarksCursor.getInt(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.IS_FOLDER))); - bookmarksContentValues.put(BookmarksDatabaseHelper.FAVORITE_ICON, bookmarksCursor.getBlob(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON))); - - // Insert the record into the export database. - exportDatabase.insert(BookmarksDatabaseHelper.BOOKMARKS_TABLE, null, bookmarksContentValues); - - // Advance to the next record. - bookmarksCursor.moveToNext(); - } - - // Close the bookmarks database. - bookmarksCursor.close(); - bookmarksDatabaseHelper.close(); - - // Prepare the preferences table SQL creation string. String CREATE_PREFERENCES_TABLE = "CREATE TABLE " + PREFERENCES_TABLE + " (" + _ID + " INTEGER PRIMARY KEY, " + @@ -239,7 +240,7 @@ public class ImportExportDatabaseHelper { SCROLL_APP_BAR + " BOOLEAN, " + DISPLAY_ADDITIONAL_APP_BAR_ICONS + " BOOLEAN, " + APP_THEME + " TEXT, " + - NIGHT_MODE + " BOOLEAN, " + + WEBVIEW_THEME + " TEXT, " + WIDE_VIEWPORT + " BOOLEAN, " + DISPLAY_WEBPAGE_IMAGES + " BOOLEAN)"; @@ -291,7 +292,7 @@ public class ImportExportDatabaseHelper { preferencesContentValues.put(SCROLL_APP_BAR, sharedPreferences.getBoolean(SCROLL_APP_BAR, true)); preferencesContentValues.put(DISPLAY_ADDITIONAL_APP_BAR_ICONS, sharedPreferences.getBoolean(DISPLAY_ADDITIONAL_APP_BAR_ICONS, false)); preferencesContentValues.put(APP_THEME, sharedPreferences.getString(APP_THEME, context.getString(R.string.app_theme_default_value))); - preferencesContentValues.put(NIGHT_MODE, sharedPreferences.getBoolean(NIGHT_MODE, false)); + preferencesContentValues.put(WEBVIEW_THEME, sharedPreferences.getString(WEBVIEW_THEME, context.getString(R.string.webview_theme_default_value))); preferencesContentValues.put(WIDE_VIEWPORT, sharedPreferences.getBoolean(WIDE_VIEWPORT, true)); preferencesContentValues.put(DISPLAY_WEBPAGE_IMAGES, sharedPreferences.getBoolean(DISPLAY_WEBPAGE_IMAGES, true)); @@ -566,9 +567,59 @@ public class ImportExportDatabaseHelper { // Set the app theme to be dark. importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + APP_THEME + " = 'Dark'"); } + + // Add the WebView theme to the domains table. This defaults to 0, which is `System default`, so a separate step isn't needed to populate the database. + importDatabase.execSQL("ALTER TABLE " + DomainsDatabaseHelper.DOMAINS_TABLE + " ADD COLUMN " + DomainsDatabaseHelper.WEBVIEW_THEME + " INTEGER"); + + // Add the WebView theme to the preferences table. + importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + WEBVIEW_THEME + " TEXT"); + + // Get the WebView theme default value string. + String webViewThemeDefaultValue = context.getString(R.string.webview_theme_default_value); + + // Set the WebView theme in the preferences table to be the default. + importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + WEBVIEW_THEME + " = " + "'" + webViewThemeDefaultValue + "'"); } } + + // Get a cursor for the bookmarks table. + Cursor importBookmarksCursor = importDatabase.rawQuery("SELECT * FROM " + BookmarksDatabaseHelper.BOOKMARKS_TABLE, null); + + // Delete the current bookmarks database. + context.deleteDatabase(BookmarksDatabaseHelper.BOOKMARKS_DATABASE); + + // Create a new bookmarks database. The `0` specifies the database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`. + BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(context, null, null, 0); + + // Move to the first bookmark. + importBookmarksCursor.moveToFirst(); + + // Copy the data from the import bookmarks cursor into the bookmarks database. + for (int i = 0; i < importBookmarksCursor.getCount(); i++) { + // Extract the record from the cursor and store the data in a ContentValues. + ContentValues bookmarksContentValues = new ContentValues(); + bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_NAME, importBookmarksCursor.getString(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))); + bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_URL, importBookmarksCursor.getString(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL))); + bookmarksContentValues.put(BookmarksDatabaseHelper.PARENT_FOLDER, importBookmarksCursor.getString(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER))); + bookmarksContentValues.put(BookmarksDatabaseHelper.DISPLAY_ORDER, importBookmarksCursor.getInt(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER))); + bookmarksContentValues.put(BookmarksDatabaseHelper.IS_FOLDER, importBookmarksCursor.getInt(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.IS_FOLDER))); + bookmarksContentValues.put(BookmarksDatabaseHelper.FAVORITE_ICON, importBookmarksCursor.getBlob(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON))); + + // Insert the record into the export database. + bookmarksDatabaseHelper.createBookmark(bookmarksContentValues); + + // Advance to the next record. + importBookmarksCursor.moveToNext(); + } + + // Close the bookmarks cursor. + importBookmarksCursor.close(); + + // Close the bookmarks database. + bookmarksDatabaseHelper.close(); + + // Get a cursor for the domains table. Cursor importDomainsCursor = importDatabase.rawQuery("SELECT * FROM " + DomainsDatabaseHelper.DOMAINS_TABLE + " ORDER BY " + DomainsDatabaseHelper.DOMAIN_NAME + " ASC", null); @@ -604,7 +655,7 @@ public class ImportExportDatabaseHelper { domainsContentValues.put(DomainsDatabaseHelper.USER_AGENT, importDomainsCursor.getString(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT))); domainsContentValues.put(DomainsDatabaseHelper.FONT_SIZE, importDomainsCursor.getInt(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE))); domainsContentValues.put(DomainsDatabaseHelper.SWIPE_TO_REFRESH, importDomainsCursor.getInt(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH))); - domainsContentValues.put(DomainsDatabaseHelper.NIGHT_MODE, importDomainsCursor.getInt(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE))); + domainsContentValues.put(DomainsDatabaseHelper.WEBVIEW_THEME, importDomainsCursor.getInt(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.WEBVIEW_THEME))); domainsContentValues.put(DomainsDatabaseHelper.WIDE_VIEWPORT, importDomainsCursor.getInt(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT))); domainsContentValues.put(DomainsDatabaseHelper.DISPLAY_IMAGES, importDomainsCursor.getInt(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES))); domainsContentValues.put(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE, importDomainsCursor.getInt(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE))); @@ -635,43 +686,6 @@ public class ImportExportDatabaseHelper { domainsDatabaseHelper.close(); - // Get a cursor for the bookmarks table. - Cursor importBookmarksCursor = importDatabase.rawQuery("SELECT * FROM " + BookmarksDatabaseHelper.BOOKMARKS_TABLE, null); - - // Delete the current bookmarks database. - context.deleteDatabase(BookmarksDatabaseHelper.BOOKMARKS_DATABASE); - - // Create a new bookmarks database. The `0` specifies the database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`. - BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(context, null, null, 0); - - // Move to the first bookmark. - importBookmarksCursor.moveToFirst(); - - // Copy the data from the import bookmarks cursor into the bookmarks database. - for (int i = 0; i < importBookmarksCursor.getCount(); i++) { - // Extract the record from the cursor and store the data in a ContentValues. - ContentValues bookmarksContentValues = new ContentValues(); - bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_NAME, importBookmarksCursor.getString(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))); - bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_URL, importBookmarksCursor.getString(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL))); - bookmarksContentValues.put(BookmarksDatabaseHelper.PARENT_FOLDER, importBookmarksCursor.getString(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER))); - bookmarksContentValues.put(BookmarksDatabaseHelper.DISPLAY_ORDER, importBookmarksCursor.getInt(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER))); - bookmarksContentValues.put(BookmarksDatabaseHelper.IS_FOLDER, importBookmarksCursor.getInt(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.IS_FOLDER))); - bookmarksContentValues.put(BookmarksDatabaseHelper.FAVORITE_ICON, importBookmarksCursor.getBlob(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON))); - - // Insert the record into the export database. - bookmarksDatabaseHelper.createBookmark(bookmarksContentValues); - - // Advance to the next record. - importBookmarksCursor.moveToNext(); - } - - // Close the bookmarks cursor. - importBookmarksCursor.close(); - - // Close the bookmarks database. - bookmarksDatabaseHelper.close(); - - // Get a cursor for the preferences table. Cursor importPreferencesCursor = importDatabase.rawQuery("SELECT * FROM " + PREFERENCES_TABLE, null); @@ -722,7 +736,7 @@ public class ImportExportDatabaseHelper { .putBoolean(SCROLL_APP_BAR, importPreferencesCursor.getInt(importPreferencesCursor.getColumnIndex(SCROLL_APP_BAR)) == 1) .putBoolean(DISPLAY_ADDITIONAL_APP_BAR_ICONS, importPreferencesCursor.getInt(importPreferencesCursor.getColumnIndex(DISPLAY_ADDITIONAL_APP_BAR_ICONS)) == 1) .putString(APP_THEME, importPreferencesCursor.getString(importPreferencesCursor.getColumnIndex(APP_THEME))) - .putBoolean(NIGHT_MODE, importPreferencesCursor.getInt(importPreferencesCursor.getColumnIndex(NIGHT_MODE)) == 1) + .putString(WEBVIEW_THEME, importPreferencesCursor.getString(importPreferencesCursor.getColumnIndex(WEBVIEW_THEME))) .putBoolean(WIDE_VIEWPORT, importPreferencesCursor.getInt(importPreferencesCursor.getColumnIndex(WIDE_VIEWPORT)) == 1) .putBoolean(DISPLAY_WEBPAGE_IMAGES, importPreferencesCursor.getInt(importPreferencesCursor.getColumnIndex(DISPLAY_WEBPAGE_IMAGES)) == 1) .apply(); diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java index 21ab2c64..c3f2fc51 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java +++ b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java @@ -1,5 +1,5 @@ /* - * Copyright © 2019 Soren Stoutner . + * Copyright © 2019-2020 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -74,9 +74,6 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild // Track the status of first-party cookies. private boolean acceptFirstPartyCookies; - // Track the domain settings JavaScript status. This can be removed once night mode does not require JavaScript. - private boolean domainSettingsJavaScriptEnabled; - // Track the resource requests. private List resourceRequests = Collections.synchronizedList(new ArrayList<>()); // Using a synchronized list makes adding resource requests thread safe. private boolean easyListEnabled; @@ -120,9 +117,6 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild // The default or favorite icon. private Bitmap favoriteOrDefaultIcon; - // Track night mode. - private boolean nightMode; - // Track swipe to refresh. private boolean swipeToRefresh; @@ -274,18 +268,6 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild } - // Domain settings JavaScript enabled. This can be removed once night mode does not require JavaScript. - public void setDomainSettingsJavaScriptEnabled(boolean status) { - // Store the domain settings JavaScript status. - domainSettingsJavaScriptEnabled = status; - } - - public boolean getDomainSettingsJavaScriptEnabled() { - // Return the domain settings JavaScript status. - return domainSettingsJavaScriptEnabled; - } - - // Resource requests. public void addResourceRequest(String[] resourceRequest) { // Add the resource request to the list. @@ -638,18 +620,6 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild } - // Night mode. - public void setNightMode(boolean status) { - // Store the night mode status. - nightMode = status; - } - - public boolean getNightMode() { - // Return the night mode status. - return nightMode; - } - - // Swipe to refresh. public void setSwipeToRefresh(boolean status) { // Store the swipe to refresh status. diff --git a/app/src/main/res/drawable/webview_theme_disabled_day.xml b/app/src/main/res/drawable/webview_dark_theme_day.xml similarity index 100% rename from app/src/main/res/drawable/webview_theme_disabled_day.xml rename to app/src/main/res/drawable/webview_dark_theme_day.xml diff --git a/app/src/main/res/drawable/webview_theme_disabled_night.xml b/app/src/main/res/drawable/webview_dark_theme_night.xml similarity index 100% rename from app/src/main/res/drawable/webview_theme_disabled_night.xml rename to app/src/main/res/drawable/webview_dark_theme_night.xml diff --git a/app/src/main/res/drawable/webview_theme_enabled_day.xml b/app/src/main/res/drawable/webview_light_theme_day.xml similarity index 100% rename from app/src/main/res/drawable/webview_theme_enabled_day.xml rename to app/src/main/res/drawable/webview_light_theme_day.xml diff --git a/app/src/main/res/drawable/webview_theme_enabled_night.xml b/app/src/main/res/drawable/webview_light_theme_night.xml similarity index 100% rename from app/src/main/res/drawable/webview_theme_enabled_night.xml rename to app/src/main/res/drawable/webview_light_theme_night.xml diff --git a/app/src/main/res/layout/domain_settings_fragment.xml b/app/src/main/res/layout/domain_settings_fragment.xml index 710c0c09..0c570ee4 100644 --- a/app/src/main/res/layout/domain_settings_fragment.xml +++ b/app/src/main/res/layout/domain_settings_fragment.xml @@ -540,8 +540,9 @@ android:textSize="13sp" /> - + - + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3e03b2ae..4a94aff8 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -161,7 +161,6 @@ Herunterziehen zum aktualisieren Breiter Anzeigebereich Bilder anzeigen - Nacht-Modus Schriftgröße Auf Seite finden Drucken @@ -328,11 +327,6 @@ Herunterziehen zum aktualisieren aktiviert Herunterziehen zum aktualisieren deaktiviert - - Standardeinstellung - Nachtmodus aktiviert - Nachtmodus deaktiviert - Standardeinstellung Breiter Anzeigebereich aktiviert diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index e2014c4f..c7f4950d 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -157,7 +157,6 @@ Deslizar para actualizar Vista amplia Mostrar imágenes - Modo noche Tamaño de fuente Buscar en página Imprimir @@ -325,11 +324,6 @@ Deslizar para actualizar habilitado Deslizar para actualizar deshabilitado - - Por defecto del sistema - Modo noche habilitado - Modo noche deshabilitado - Por defecto del sistema Vista amplia habilitada diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d3c32165..861c4457 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -158,7 +158,6 @@ Glisser pour actualiser Fenêtre large Afficher les images - Mode nuit Police Chercher sur la page Imprimer @@ -325,11 +324,6 @@ Glisser pour actualiser activé Glisser pour actualiser déactivé - - Réglages systèmes - Mode nuit activé - Mode nuit désactivé - Réglages systèmes Mode fenêtre large activé diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 8208d547..a87b07c3 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -157,7 +157,6 @@ Swipe per aggiornare Finestra grande Mostra immagini - Modalità Notte Dimensione font Cerca nella pagina Stampa @@ -324,11 +323,6 @@ Swipe per aggiornare abilitato Swipe per aggiornare disabilitato - - Impostazioni di default - Modalità Notte abilitata - Modalità Notte disabilitata - Impostazioni di default Finestra grande abilitata diff --git a/app/src/main/res/values-night-v23/styles.xml b/app/src/main/res/values-night-v23/styles.xml index e9035a5a..12616d42 100644 --- a/app/src/main/res/values-night-v23/styles.xml +++ b/app/src/main/res/values-night-v23/styles.xml @@ -75,7 +75,6 @@ @drawable/home_enabled_night @drawable/search_enabled_night @drawable/user_agent_night - @drawable/webview_theme_enabled_night