From d0d1b8d83a433a323d01ab8c745ab385043ffc54 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Fri, 30 Apr 2021 14:07:19 -0700 Subject: [PATCH] Add the option to download with an external app. https://redmine.stoutner.com/issues/698 --- .../activities/MainWebViewActivity.java | 157 +++--- .../fragments/SettingsFragment.java | 457 +++++++++++------- .../helpers/ImportExportDatabaseHelper.java | 7 + ...ownload_with_external_app_disabled_day.xml | 26 + ...nload_with_external_app_disabled_night.xml | 26 + ...ownload_with_external_app_enabled_day.xml} | 2 +- ...wnload_with_external_app_enabled_night.xml | 26 + .../main/res/menu/webview_navigation_menu.xml | 2 +- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/xml/preferences.xml | 6 + 14 files changed, 473 insertions(+), 243 deletions(-) create mode 100644 app/src/main/res/drawable/download_with_external_app_disabled_day.xml create mode 100644 app/src/main/res/drawable/download_with_external_app_disabled_night.xml rename app/src/main/res/drawable/{clear_and_exit.xml => download_with_external_app_enabled_day.xml} (100%) create mode 100644 app/src/main/res/drawable/download_with_external_app_enabled_night.xml 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 a321b6c8..ed25a37d 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -247,39 +247,20 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private ArrayList> ultraList; private ArrayList> ultraPrivacy; - // `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`. + // Declare the class variables + private BroadcastReceiver orbotStatusBroadcastReceiver; private String webViewDefaultUserAgent; - - // The incognito mode is set in `applyAppSettings()` and used in `initializeWebView()`. private boolean incognitoModeEnabled; - - // The full screen browsing mode tracker is set it `applyAppSettings()` and used in `initializeWebView()`. private boolean fullScreenBrowsingModeEnabled; - - // `inFullScreenBrowsingMode` is used in `onCreate()`, `onConfigurationChanged()`, and `applyAppSettings()`. private boolean inFullScreenBrowsingMode; - - // The app bar trackers are set in `applyAppSettings()` and used in `initializeWebView()`. + private boolean downloadWithExternalApp; private boolean hideAppBar; private boolean scrollAppBar; - - // The loading new intent tracker is set in `onNewIntent()` and used in `setCurrentWebView()`. private boolean loadingNewIntent; - - // `reapplyDomainSettingsOnRestart` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, and `onAddDomain()`, . private boolean reapplyDomainSettingsOnRestart; - - // `reapplyAppSettingsOnRestart` is used in `onNavigationItemSelected()` and `onRestart()`. private boolean reapplyAppSettingsOnRestart; - - // `displayingFullScreenVideo` is used in `onCreate()` and `onResume()`. private boolean displayingFullScreenVideo; - - // `orbotStatusBroadcastReceiver` is used in `onCreate()` and `onDestroy()`. - private BroadcastReceiver orbotStatusBroadcastReceiver; - - // The waiting for proxy boolean is used in `onResume()`, `initializeApp()` and `applyProxy()`. - private boolean waitingForProxy = false; + private boolean waitingForProxy; // The action bar drawer toggle is initialized in `onCreate()` and used in `onResume()`. private ActionBarDrawerToggle actionBarDrawerToggle; @@ -1729,9 +1710,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Consume the event. return true; } else if (menuItemId == R.id.save_url) { // Save URL. - // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. - new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), - currentWebView.getAcceptCookies()).execute(currentWebView.getCurrentUrl()); + // Check the download preference. + if (downloadWithExternalApp) { // Download with an external app. + downloadUrlWithExternalApp(currentWebView.getCurrentUrl()); + } else { // Handle the download inside of Privacy Browser. + // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. + new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), + currentWebView.getAcceptCookies()).execute(currentWebView.getCurrentUrl()); + } // Consume the event. return true; @@ -2242,9 +2228,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Add a Save URL entry. menu.add(R.string.save_url).setOnMenuItemClickListener((MenuItem item) -> { - // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. - new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), - currentWebView.getAcceptCookies()).execute(linkUrl); + // Check the download preference. + if (downloadWithExternalApp) { // Download with an external app. + downloadUrlWithExternalApp(linkUrl); + } else { // Handle the download inside of Privacy Browser. + // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. + new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), + currentWebView.getAcceptCookies()).execute(linkUrl); + } // Consume the event. return true; @@ -2309,9 +2300,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Add a Save Image entry. menu.add(R.string.save_image).setOnMenuItemClickListener((MenuItem item) -> { - // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. - new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), - currentWebView.getAcceptCookies()).execute(imageUrl); + // Check the download preference. + if (downloadWithExternalApp) { // Download with an external app. + downloadUrlWithExternalApp(imageUrl); + } else { // Handle the download inside of Privacy Browser. + // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. + new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), + currentWebView.getAcceptCookies()).execute(imageUrl); + } // Consume the event. return true; @@ -2409,9 +2405,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Add a Save Image entry. menu.add(R.string.save_image).setOnMenuItemClickListener((MenuItem item) -> { - // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. - new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), - currentWebView.getAcceptCookies()).execute(imageUrl); + // Check the download preference. + if (downloadWithExternalApp) { // Download with an external app. + downloadUrlWithExternalApp(imageUrl); + } else { // Handle the download inside of Privacy Browser. + // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. + new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), + currentWebView.getAcceptCookies()).execute(imageUrl); + } // Consume the event. return true; @@ -2431,9 +2432,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Add a Save URL entry. menu.add(R.string.save_url).setOnMenuItemClickListener((MenuItem item) -> { - // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. - new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), - currentWebView.getAcceptCookies()).execute(linkUrl); + // Check the download preference. + if (downloadWithExternalApp) { // Download with an external app. + downloadUrlWithExternalApp(linkUrl); + } else { // Handle the download inside of Privacy Browser. + // Prepare the save dialog. The dialog will be displayed once the file size and the content disposition have been acquired. + new PrepareSaveDialog(this, this, getSupportFragmentManager(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(), + currentWebView.getAcceptCookies()).execute(linkUrl); + } // Consume the event. return true; @@ -3017,7 +3023,20 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } } - @Override + private void downloadUrlWithExternalApp(String url) { + // Create a download intent. Not specifying the action type will display the maximum number of options. + Intent downloadIntent = new Intent(); + + // Set the URI and the mime type. + downloadIntent.setDataAndType(Uri.parse(url), "text/html"); + + // Flag the intent to open in a new task. + downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + // Show the chooser. + startActivity(Intent.createChooser(downloadIntent, getString(R.string.download_with_external_app))); + } + public void onSaveWebpage(int saveType, @NonNull String originalUrlString, DialogFragment dialogFragment) { // Get the dialog. Dialog dialog = dialogFragment.getDialog(); @@ -3542,6 +3561,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook sanitizeTwitterAmpRedirects = sharedPreferences.getBoolean("twitter_amp_redirects", true); proxyMode = sharedPreferences.getString("proxy", getString(R.string.proxy_default_value)); fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false); + downloadWithExternalApp = sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false); hideAppBar = sharedPreferences.getBoolean("hide_app_bar", true); scrollAppBar = sharedPreferences.getBoolean("scroll_app_bar", true); @@ -5311,38 +5331,43 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Allow the downloading of files. nestedScrollWebView.setDownloadListener((String downloadUrl, String userAgent, String contentDisposition, String mimetype, long contentLength) -> { - // Define a formatted file size string. - String formattedFileSizeString; - - // Process the content length if it contains data. - if (contentLength > 0) { // The content length is greater than 0. - // Format the content length as a string. - formattedFileSizeString = NumberFormat.getInstance().format(contentLength) + " " + getString(R.string.bytes); - } else { // The content length is not greater than 0. - // Set the formatted file size string to be `unknown size`. - formattedFileSizeString = getString(R.string.unknown_size); - } + // Check the download preference. + if (downloadWithExternalApp) { // Download with an external app. + downloadUrlWithExternalApp(downloadUrl); + } else { // Handle the download inside of Privacy Browser. + // Define a formatted file size string. + String formattedFileSizeString; + + // Process the content length if it contains data. + if (contentLength > 0) { // The content length is greater than 0. + // Format the content length as a string. + formattedFileSizeString = NumberFormat.getInstance().format(contentLength) + " " + getString(R.string.bytes); + } else { // The content length is not greater than 0. + // Set the formatted file size string to be `unknown size`. + formattedFileSizeString = getString(R.string.unknown_size); + } - // Get the file name from the content disposition. - String fileNameString = PrepareSaveDialog.getFileNameFromHeaders(this, contentDisposition, mimetype, downloadUrl); + // Get the file name from the content disposition. + String fileNameString = PrepareSaveDialog.getFileNameFromHeaders(this, contentDisposition, mimetype, downloadUrl); - // Prevent the dialog from displaying if the app window is not visible. - // The download listener continues to function even when the WebView is paused. Attempting to display a dialog in that state leads to a crash. - while (!activity.getWindow().isActive()) { - try { - // The window is not active. Wait 1 second. - wait(1000); - } catch (InterruptedException e) { - // Do nothing. + // Prevent the dialog from displaying if the app window is not visible. + // The download listener continues to function even when the WebView is paused. Attempting to display a dialog in that state leads to a crash. + while (!activity.getWindow().isActive()) { + try { + // The window is not active. Wait 1 second. + wait(1000); + } catch (InterruptedException e) { + // Do nothing. + } } - } - // Instantiate the save dialog. - DialogFragment saveDialogFragment = SaveWebpageDialog.saveWebpage(SaveWebpageDialog.SAVE_URL, downloadUrl, formattedFileSizeString, fileNameString, userAgent, - nestedScrollWebView.getAcceptCookies()); + // Instantiate the save dialog. + DialogFragment saveDialogFragment = SaveWebpageDialog.saveWebpage(SaveWebpageDialog.SAVE_URL, downloadUrl, formattedFileSizeString, fileNameString, userAgent, + nestedScrollWebView.getAcceptCookies()); - // Show the save dialog. It must be named `save_dialog` so that the file picker can update the file name. - saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog)); + // Show the save dialog. It must be named `save_dialog` so that the file picker can update the file name. + saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog)); + } }); // Update the find on page count. 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 486a7053..c6a1493e 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java @@ -45,10 +45,60 @@ import com.stoutner.privacybrowser.activities.MainWebViewActivity; import com.stoutner.privacybrowser.helpers.ProxyHelper; public class SettingsFragment extends PreferenceFragmentCompat { - // Define the class variables. - private SharedPreferences.OnSharedPreferenceChangeListener preferencesListener; - private SharedPreferences savedPreferences; + // Declare the class variables. private int currentThemeStatus; + private String defaultUserAgent; + private ArrayAdapter userAgentNamesArray; + private String[] translatedUserAgentNamesArray; + private String[] userAgentDataArray; + private String[] appThemeEntriesStringArray; + private String[] appThemeEntryValuesStringArray; + private String[] webViewThemeEntriesStringArray; + private String[] webViewThemeEntryValuesStringArray; + private SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener; + + // Declare the class views. + private Preference javaScriptPreference; + private Preference cookiesPreference; + private Preference domStoragePreference; + private Preference formDataPreference; // The form data preference can be removed once the minimum API >= 26. + private Preference userAgentPreference; + private Preference customUserAgentPreference; + private Preference incognitoModePreference; + private Preference allowScreenshotsPreference; + private Preference easyListPreference; + private Preference easyPrivacyPreference; + private Preference fanboyAnnoyanceListPreference; + private Preference fanboySocialBlockingListPreference; + private Preference ultraListPreference; + private Preference ultraPrivacyPreference; + private Preference blockAllThirdPartyRequestsPreference; + private Preference googleAnalyticsPreference; + private Preference facebookClickIdsPreference; + private Preference twitterAmpRedirectsPreference; + private Preference searchPreference; + private Preference searchCustomURLPreference; + private Preference proxyPreference; + private Preference proxyCustomUrlPreference; + private Preference fullScreenBrowsingModePreference; + private Preference hideAppBarPreference; + private Preference clearEverythingPreference; + private Preference clearCookiesPreference; + private Preference clearDomStoragePreference; + private Preference clearFormDataPreference; // The clear form data preference can be removed once the minimum API >= 26. + private Preference clearLogcatPreference; + private Preference clearCachePreference; + private Preference homepagePreference; + private Preference fontSizePreference; + private Preference openIntentsInNewTabPreference; + private Preference swipeToRefreshPreference; + private Preference downloadWithExternalAppPreference; + private Preference scrollAppBarPreference; + private Preference displayAdditionalAppBarIconsPreference; + private Preference appThemePreference; + private Preference webViewThemePreference; + private Preference wideViewportPreference; + private Preference displayWebpageImagesPreference; @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { @@ -61,57 +111,57 @@ public class SettingsFragment extends PreferenceFragmentCompat { // Remove the lint warning below that `getApplicationContext()` might produce a null pointer exception. assert activity != null; - // Get a handle for the context and the resources. - Context context = activity.getApplicationContext(); + // Get a handle for the resources. Resources resources = getResources(); // Get the current theme status. currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; - // Initialize savedPreferences. - savedPreferences = getPreferenceScreen().getSharedPreferences(); + // // Get a handle for the shared preferences. + SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); // Get handles for the preferences. - Preference javaScriptPreference = findPreference("javascript"); - Preference cookiesPreference = findPreference(getString(R.string.cookies_key)); - Preference domStoragePreference = findPreference("dom_storage"); - Preference formDataPreference = findPreference("save_form_data"); // The form data preference can be removed once the minimum API >= 26. - Preference userAgentPreference = findPreference("user_agent"); - Preference customUserAgentPreference = findPreference("custom_user_agent"); - Preference incognitoModePreference = findPreference("incognito_mode"); - Preference allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key)); - Preference easyListPreference = findPreference("easylist"); - Preference easyPrivacyPreference = findPreference("easyprivacy"); - Preference fanboyAnnoyanceListPreference = findPreference("fanboys_annoyance_list"); - Preference fanboySocialBlockingListPreference = findPreference("fanboys_social_blocking_list"); - Preference ultraListPreference = findPreference("ultralist"); - Preference ultraPrivacyPreference = findPreference("ultraprivacy"); - Preference blockAllThirdPartyRequestsPreference = findPreference("block_all_third_party_requests"); - Preference googleAnalyticsPreference = findPreference("google_analytics"); - Preference facebookClickIdsPreference = findPreference("facebook_click_ids"); - Preference twitterAmpRedirectsPreference = findPreference("twitter_amp_redirects"); - Preference searchPreference = findPreference("search"); - Preference searchCustomURLPreference = findPreference("search_custom_url"); - Preference proxyPreference = findPreference("proxy"); - Preference proxyCustomUrlPreference = findPreference("proxy_custom_url"); - Preference fullScreenBrowsingModePreference = findPreference("full_screen_browsing_mode"); - Preference hideAppBarPreference = findPreference("hide_app_bar"); - Preference clearEverythingPreference = findPreference("clear_everything"); - Preference clearCookiesPreference = findPreference("clear_cookies"); - Preference clearDomStoragePreference = findPreference("clear_dom_storage"); - Preference clearFormDataPreference = findPreference("clear_form_data"); // The clear form data preference can be removed once the minimum API >= 26. - Preference clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key)); - Preference clearCachePreference = findPreference("clear_cache"); - Preference homepagePreference = findPreference("homepage"); - Preference fontSizePreference = findPreference("font_size"); - Preference openIntentsInNewTabPreference = findPreference("open_intents_in_new_tab"); - Preference swipeToRefreshPreference = findPreference("swipe_to_refresh"); - Preference scrollAppBarPreference = findPreference("scroll_app_bar"); - Preference displayAdditionalAppBarIconsPreference = findPreference("display_additional_app_bar_icons"); - Preference appThemePreference = findPreference("app_theme"); - Preference webViewThemePreference = findPreference("webview_theme"); - Preference wideViewportPreference = findPreference("wide_viewport"); - Preference displayWebpageImagesPreference = findPreference("display_webpage_images"); + javaScriptPreference = findPreference("javascript"); + cookiesPreference = findPreference(getString(R.string.cookies_key)); + domStoragePreference = findPreference("dom_storage"); + formDataPreference = findPreference("save_form_data"); // The form data preference can be removed once the minimum API >= 26. + userAgentPreference = findPreference("user_agent"); + customUserAgentPreference = findPreference("custom_user_agent"); + incognitoModePreference = findPreference("incognito_mode"); + allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key)); + easyListPreference = findPreference("easylist"); + easyPrivacyPreference = findPreference("easyprivacy"); + fanboyAnnoyanceListPreference = findPreference("fanboys_annoyance_list"); + fanboySocialBlockingListPreference = findPreference("fanboys_social_blocking_list"); + ultraListPreference = findPreference("ultralist"); + ultraPrivacyPreference = findPreference("ultraprivacy"); + blockAllThirdPartyRequestsPreference = findPreference("block_all_third_party_requests"); + googleAnalyticsPreference = findPreference("google_analytics"); + facebookClickIdsPreference = findPreference("facebook_click_ids"); + twitterAmpRedirectsPreference = findPreference("twitter_amp_redirects"); + searchPreference = findPreference("search"); + searchCustomURLPreference = findPreference("search_custom_url"); + proxyPreference = findPreference("proxy"); + proxyCustomUrlPreference = findPreference("proxy_custom_url"); + fullScreenBrowsingModePreference = findPreference("full_screen_browsing_mode"); + hideAppBarPreference = findPreference("hide_app_bar"); + clearEverythingPreference = findPreference("clear_everything"); + clearCookiesPreference = findPreference("clear_cookies"); + clearDomStoragePreference = findPreference("clear_dom_storage"); + clearFormDataPreference = findPreference("clear_form_data"); // The clear form data preference can be removed once the minimum API >= 26. + clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key)); + clearCachePreference = findPreference("clear_cache"); + homepagePreference = findPreference("homepage"); + fontSizePreference = findPreference("font_size"); + openIntentsInNewTabPreference = findPreference("open_intents_in_new_tab"); + swipeToRefreshPreference = findPreference("swipe_to_refresh"); + downloadWithExternalAppPreference = findPreference(getString(R.string.download_with_external_app_key)); + scrollAppBarPreference = findPreference("scroll_app_bar"); + displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key)); + appThemePreference = findPreference("app_theme"); + webViewThemePreference = findPreference("webview_theme"); + wideViewportPreference = findPreference("wide_viewport"); + displayWebpageImagesPreference = findPreference("display_webpage_images"); // Remove the lint warnings below that the preferences might be null. assert javaScriptPreference != null; @@ -148,6 +198,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { assert fontSizePreference != null; assert openIntentsInNewTabPreference != null; assert swipeToRefreshPreference != null; + assert downloadWithExternalAppPreference != null; assert scrollAppBarPreference != null; assert displayAdditionalAppBarIconsPreference != null; assert appThemePreference != null; @@ -160,16 +211,16 @@ public class SettingsFragment extends PreferenceFragmentCompat { domStoragePreference.setDependency("javascript"); // Get strings from the preferences. - String userAgentName = savedPreferences.getString("user_agent", getString(R.string.user_agent_default_value)); - String searchString = savedPreferences.getString("search", getString(R.string.search_default_value)); - String proxyString = savedPreferences.getString("proxy", getString(R.string.proxy_default_value)); + String userAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value)); + String searchString = sharedPreferences.getString("search", getString(R.string.search_default_value)); + String proxyString = sharedPreferences.getString("proxy", getString(R.string.proxy_default_value)); // Get booleans that are used in multiple places from the preferences. - boolean javaScriptEnabled = savedPreferences.getBoolean("javascript", false); - boolean fanboyAnnoyanceListEnabled = savedPreferences.getBoolean("fanboys_annoyance_list", true); - boolean fanboySocialBlockingEnabled = savedPreferences.getBoolean("fanboys_social_blocking_list", true); - boolean fullScreenBrowsingMode = savedPreferences.getBoolean("full_screen_browsing_mode", false); - boolean clearEverything = savedPreferences.getBoolean("clear_everything", true); + boolean javaScriptEnabled = sharedPreferences.getBoolean("javascript", false); + boolean fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboys_annoyance_list", true); + boolean fanboySocialBlockingEnabled = sharedPreferences.getBoolean("fanboys_social_blocking_list", true); + boolean fullScreenBrowsingMode = sharedPreferences.getBoolean("full_screen_browsing_mode", false); + boolean clearEverything = sharedPreferences.getBoolean("clear_everything", true); // Remove the form data preferences if the API is >= 26 as they no longer do anything. if (Build.VERSION.SDK_INT >= 26) { @@ -199,10 +250,13 @@ public class SettingsFragment extends PreferenceFragmentCompat { // Get a handle for a bare WebView. WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview); + // Get the default user agent. + defaultUserAgent = bareWebView.getSettings().getUserAgentString(); + // Get the user agent arrays. - ArrayAdapter userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item); - String[] translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names); - String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data); + userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item); + translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names); + userAgentDataArray = resources.getStringArray(R.array.user_agent_data); // Get the array position of the user agent name. int userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName); @@ -216,7 +270,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT: // Get the user agent text from the webview (which changes based on the version of Android and WebView installed). - userAgentPreference.setSummary(translatedUserAgentNamesArray[userAgentArrayPosition] + ":\n" + bareWebView.getSettings().getUserAgentString()); + userAgentPreference.setSummary(translatedUserAgentNamesArray[userAgentArrayPosition] + ":\n" + defaultUserAgent); break; case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT: @@ -230,7 +284,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the summary text for the custom user agent preference. - customUserAgentPreference.setSummary(savedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value))); + customUserAgentPreference.setSummary(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value))); // Only enable the custom user agent preference if the user agent is set to `Custom`. customUserAgentPreference.setEnabled(userAgentPreference.getSummary().equals(getString(R.string.custom_user_agent))); @@ -246,7 +300,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the summary text for the search custom URL (the default is `""`). - searchCustomURLPreference.setSummary(savedPreferences.getString("search_custom_url", getString(R.string.search_custom_url_default_value))); + searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", getString(R.string.search_custom_url_default_value))); // Only enable the search custom URL preference if the search is set to `Custom URL`. searchCustomURLPreference.setEnabled(searchString.equals("Custom URL")); @@ -276,7 +330,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the summary text for the custom proxy URL. - proxyCustomUrlPreference.setSummary(savedPreferences.getString("proxy_custom_url", getString(R.string.proxy_custom_url_default_value))); + proxyCustomUrlPreference.setSummary(sharedPreferences.getString("proxy_custom_url", getString(R.string.proxy_custom_url_default_value))); // Only enable the custom proxy URL if a custom proxy is selected. proxyCustomUrlPreference.setEnabled(proxyString.equals("Custom")); @@ -291,19 +345,19 @@ public class SettingsFragment extends PreferenceFragmentCompat { // Set the homepage URL as the summary text for the homepage preference. - homepagePreference.setSummary(savedPreferences.getString("homepage", getString(R.string.homepage_default_value))); + homepagePreference.setSummary(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value))); // Set the font size as the summary text for the preference. - fontSizePreference.setSummary(savedPreferences.getString("font_size", getString(R.string.font_size_default_value)) + "%"); + fontSizePreference.setSummary(sharedPreferences.getString("font_size", getString(R.string.font_size_default_value)) + "%"); // Get the app theme string arrays. - String[] appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries); - String[] appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values); + appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries); + appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values); // Get the current app theme. - String currentAppTheme = savedPreferences.getString("app_theme", getString(R.string.app_theme_default_value)); + String currentAppTheme = sharedPreferences.getString("app_theme", getString(R.string.app_theme_default_value)); // Define an app theme entry number. int appThemeEntryNumber; @@ -325,11 +379,11 @@ public class SettingsFragment extends PreferenceFragmentCompat { // Get the WebView theme string arrays. - String[] webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries); - String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values); + webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries); + webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values); // Get the current WebView theme. - String currentWebViewTheme = savedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value)); + String currentWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value)); // Define a WebView theme entry number. int webViewThemeEntryNumber; @@ -370,7 +424,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the cookies icon. - if (savedPreferences.getBoolean(getString(R.string.cookies_key), false)) { + if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false)) { cookiesPreference.setIcon(R.drawable.cookies_enabled); } else { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { @@ -382,7 +436,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { // Set the DOM storage icon. if (javaScriptEnabled) { // The preference is enabled. - if (savedPreferences.getBoolean("dom_storage", false)) { // DOM storage is enabled. + if (sharedPreferences.getBoolean("dom_storage", false)) { // DOM storage is enabled. domStoragePreference.setIcon(R.drawable.dom_storage_enabled); } else { // DOM storage is disabled. if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { @@ -401,7 +455,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { // Set the save form data icon if API < 26. Save form data has no effect on API >= 26. if (Build.VERSION.SDK_INT < 26) { - if (savedPreferences.getBoolean("save_form_data", false)) { + if (sharedPreferences.getBoolean("save_form_data", false)) { formDataPreference.setIcon(R.drawable.form_data_enabled); } else { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { @@ -428,7 +482,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the incognito mode icon. - if (savedPreferences.getBoolean("incognito_mode", false)) { + if (sharedPreferences.getBoolean("incognito_mode", false)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled_night); } else { @@ -443,7 +497,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the allow screenshots icon. - if (savedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)) { + if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled_day); } else { @@ -458,7 +512,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the EasyList icon. - if (savedPreferences.getBoolean("easylist", true)) { + if (sharedPreferences.getBoolean("easylist", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { easyListPreference.setIcon(R.drawable.block_ads_enabled_night); } else { @@ -473,7 +527,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the EasyPrivacy icon. - if (savedPreferences.getBoolean("easyprivacy", true)) { + if (sharedPreferences.getBoolean("easyprivacy", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled_night); } else { @@ -527,7 +581,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the UltraList icon. - if (savedPreferences.getBoolean("ultralist", true)){ + if (sharedPreferences.getBoolean("ultralist", true)){ if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { ultraListPreference.setIcon(R.drawable.block_ads_enabled_night); } else { @@ -542,7 +596,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the UltraPrivacy icon. - if (savedPreferences.getBoolean("ultraprivacy", true)) { + if (sharedPreferences.getBoolean("ultraprivacy", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled_night); } else { @@ -557,7 +611,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the block all third-party requests icon. - if (savedPreferences.getBoolean("block_all_third_party_requests", false)) { + if (sharedPreferences.getBoolean("block_all_third_party_requests", false)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled_night); } else { @@ -572,7 +626,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the Google Analytics icon according to the theme. - if (savedPreferences.getBoolean("google_analytics", true)) { + if (sharedPreferences.getBoolean("google_analytics", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { googleAnalyticsPreference.setIcon(R.drawable.modify_url_enabled_night); } else { @@ -587,7 +641,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the Facebook Click IDs icon according to the theme. - if (savedPreferences.getBoolean("facebook_click_ids", true)) { + if (sharedPreferences.getBoolean("facebook_click_ids", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { facebookClickIdsPreference.setIcon(R.drawable.modify_url_enabled_night); } else { @@ -602,7 +656,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the Twitter AMP redirects icon according to the theme. - if (savedPreferences.getBoolean("twitter_amp_redirects", true)) { + if (sharedPreferences.getBoolean("twitter_amp_redirects", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { twitterAmpRedirectsPreference.setIcon(R.drawable.modify_url_enabled_night); } else { @@ -680,7 +734,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the hide app bar icon. - if (savedPreferences.getBoolean("hide_app_bar", true)) { // Hide app bar is enabled. + if (sharedPreferences.getBoolean("hide_app_bar", true)) { // Hide app bar is enabled. // Set the icon according to the theme. if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { hideAppBarPreference.setIcon(R.drawable.app_bar_enabled_night); @@ -718,7 +772,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the clear cookies preference icon. - if (clearEverything || savedPreferences.getBoolean("clear_cookies", true)) { + if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { clearCookiesPreference.setIcon(R.drawable.cookies_cleared_day); } else { @@ -729,7 +783,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the clear DOM storage preference icon. - if (clearEverything || savedPreferences.getBoolean("clear_dom_storage", true)) { + if (clearEverything || sharedPreferences.getBoolean("clear_dom_storage", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { clearDomStoragePreference.setIcon(R.drawable.dom_storage_cleared_night); } else { @@ -741,7 +795,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { // Set the clear form data preference icon if the API < 26. It has no effect on newer versions of Android. if (Build.VERSION.SDK_INT < 26) { - if (clearEverything || savedPreferences.getBoolean("clear_form_data", true)) { + if (clearEverything || sharedPreferences.getBoolean("clear_form_data", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { clearFormDataPreference.setIcon(R.drawable.form_data_cleared_night); } else { @@ -753,7 +807,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the clear logcat preference icon. - if (clearEverything || savedPreferences.getBoolean(getString(R.string.clear_logcat_key), true)) { + if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { clearLogcatPreference.setIcon(R.drawable.bug_cleared_day); } else { @@ -764,7 +818,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the clear cache preference icon. - if (clearEverything || savedPreferences.getBoolean("clear_cache", true)) { + if (clearEverything || sharedPreferences.getBoolean("clear_cache", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { clearCachePreference.setIcon(R.drawable.cache_cleared_night); } else { @@ -775,7 +829,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the open intents in new tab preference icon. - if (savedPreferences.getBoolean("open_intents_in_new_tab", true)) { + if (sharedPreferences.getBoolean("open_intents_in_new_tab", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled_night); } else { @@ -790,47 +844,62 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the swipe to refresh preference icon. - if (savedPreferences.getBoolean("swipe_to_refresh", true)) { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled_night); - } else { + if (sharedPreferences.getBoolean("swipe_to_refresh", true)) { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled_day); + } else { + swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled_night); } } else { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled_day); + } else { swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled_night); + } + } + + // Set the download with external app preference icon. + if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false)) { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled_day); } else { - swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled_day); + downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled_night); + } + } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled_day); + } else { + downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled_night); } } // Set the scroll app bar preference icon. - if (savedPreferences.getBoolean("scroll_app_bar", true)) { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled_night); - } else { + if (sharedPreferences.getBoolean("scroll_app_bar", true)) { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled_day); + } else { + scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled_night); } } else { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled_night); - } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled_day); + } else { + scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled_night); } } // Set the display additional app bar icons preference icon. - if (savedPreferences.getBoolean("display_additional_app_bar_icons", false)) { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled_night); - } else { + if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false)) { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled_day); + } else { + displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled_night); } } else { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled_night); - } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled_day); + } else { + displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled_night); } } @@ -864,7 +933,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the wide viewport preference icon. - if (savedPreferences.getBoolean("wide_viewport", true)) { + if (sharedPreferences.getBoolean("wide_viewport", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled_night); } else { @@ -879,7 +948,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Set the display webpage images preference icon. - if (savedPreferences.getBoolean("display_webpage_images", true)) { + if (sharedPreferences.getBoolean("display_webpage_images", true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { displayWebpageImagesPreference.setIcon(R.drawable.images_enabled_night); } else { @@ -893,9 +962,46 @@ public class SettingsFragment extends PreferenceFragmentCompat { } } + // Get the shared preferences change listener. + sharedPreferenceChangeListener = getSharedPreferencesChangeListener(requireContext()); + + // Register the listener. + sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); + } - // Listen for preference changes. - preferencesListener = (SharedPreferences sharedPreferences, String key) -> { + // The listener should be unregistered when the app is paused. + @Override + public void onPause() { + // Run the default commands. + super.onPause(); + + // Get a handle for the shared preferences. + SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); + + // Unregister the shared preferences listener. + sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); + } + + // The listener should be re-registered when the app is resumed. + @Override + public void onResume() { + // Run the default commands. + super.onResume(); + + // Get a new shared preferences change listener. + sharedPreferenceChangeListener = getSharedPreferencesChangeListener(requireContext()); + + // Get a handle for the shared preferences. + SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); + + // Re-register the shared preferences listener. + sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); + } + + // The context must be passed to the shared preference change listener or else any calls to the system `getString()` will crash if the app has been restarted. + private SharedPreferences.OnSharedPreferenceChangeListener getSharedPreferencesChangeListener(Context context) { + // Return the shared preference change listener. + return (SharedPreferences sharedPreferences, String key) -> { switch (key) { case "javascript": // Update the icons and the DOM storage preference status. @@ -934,7 +1040,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "cookies": // Update the icon. - if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false)) { + if (sharedPreferences.getBoolean(context.getString(R.string.cookies_key), false)) { cookiesPreference.setIcon(R.drawable.cookies_enabled); } else { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { @@ -974,7 +1080,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "user_agent": // Get the new user agent name. - String newUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value)); + String newUserAgentName = sharedPreferences.getString("user_agent", context.getString(R.string.user_agent_default_value)); // Get the array position for the new user agent name. int newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName); @@ -986,7 +1092,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { switch (newUserAgentArrayPosition) { case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT: // Get the user agent text from the webview (which changes based on the version of Android and WebView installed). - userAgentPreference.setSummary(translatedNewUserAgentName + ":\n" + bareWebView.getSettings().getUserAgentString()); + userAgentPreference.setSummary(translatedNewUserAgentName + ":\n" + defaultUserAgent); // Disable the custom user agent preference. customUserAgentPreference.setEnabled(false); @@ -1032,7 +1138,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "custom_user_agent": // Set the new custom user agent as the summary text for the preference. - customUserAgentPreference.setSummary(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value))); + customUserAgentPreference.setSummary(sharedPreferences.getString("custom_user_agent", context.getString(R.string.custom_user_agent_default_value))); break; case "incognito_mode": @@ -1054,7 +1160,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "allow_screenshots": // Update the icon. - if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)) { + if (sharedPreferences.getBoolean(context.getString(R.string.allow_screenshots_key), false)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled_day); } else { @@ -1069,7 +1175,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Create an intent to restart Privacy Browser. - Intent allowScreenshotsRestartIntent = getActivity().getParentActivityIntent(); + Intent allowScreenshotsRestartIntent = requireActivity().getParentActivityIntent(); // Assert that the intent is not null to remove the lint error below. assert allowScreenshotsRestartIntent != null; @@ -1295,7 +1401,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "search": // Store the new search string. - String newSearchString = sharedPreferences.getString("search", getString(R.string.search_default_value)); + String newSearchString = sharedPreferences.getString("search", context.getString(R.string.search_default_value)); // Update the search and search custom URL preferences. if (newSearchString.equals("Custom URL")) { // `Custom URL` is selected. @@ -1329,33 +1435,33 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "search_custom_url": // Set the new search custom URL as the summary text for the preference. - searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", getString(R.string.search_custom_url_default_value))); + searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", context.getString(R.string.search_custom_url_default_value))); break; case "proxy": // Get current proxy string. - String currentProxyString = sharedPreferences.getString("proxy", getString(R.string.proxy_default_value)); + String currentProxyString = sharedPreferences.getString("proxy", context.getString(R.string.proxy_default_value)); // Update the summary text for the proxy preference. switch (currentProxyString) { case ProxyHelper.NONE: - proxyPreference.setSummary(getString(R.string.no_proxy_enabled)); + proxyPreference.setSummary(context.getString(R.string.no_proxy_enabled)); break; case ProxyHelper.TOR: if (Build.VERSION.SDK_INT == 19) { // Proxying through SOCKS doesn't work on Android KitKat. - proxyPreference.setSummary(getString(R.string.tor_enabled_kitkat)); + proxyPreference.setSummary(context.getString(R.string.tor_enabled_kitkat)); } else { - proxyPreference.setSummary(getString(R.string.tor_enabled)); + proxyPreference.setSummary(context.getString(R.string.tor_enabled)); } break; case ProxyHelper.I2P: - proxyPreference.setSummary(getString(R.string.i2p_enabled)); + proxyPreference.setSummary(context.getString(R.string.i2p_enabled)); break; case ProxyHelper.CUSTOM: - proxyPreference.setSummary(getString(R.string.custom_proxy)); + proxyPreference.setSummary(context.getString(R.string.custom_proxy)); break; } @@ -1404,7 +1510,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "proxy_custom_url": // Set the summary text for the proxy custom URL. - proxyCustomUrlPreference.setSummary(sharedPreferences.getString("proxy_custom_url", getString(R.string.proxy_custom_url_default_value))); + proxyCustomUrlPreference.setSummary(sharedPreferences.getString("proxy_custom_url", context.getString(R.string.proxy_custom_url_default_value))); break; case "full_screen_browsing_mode": @@ -1521,7 +1627,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } // Update the clear logcat preference icon. - if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true)) { + if (newClearEverythingBoolean || sharedPreferences.getBoolean(context.getString(R.string.clear_logcat_key), true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { clearLogcatPreference.setIcon(R.drawable.bug_cleared_day); } else { @@ -1585,7 +1691,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "clear_logcat": // Update the icon. - if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true)) { + if (sharedPreferences.getBoolean(context.getString(R.string.clear_logcat_key), true)) { if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { clearLogcatPreference.setIcon(R.drawable.bug_cleared_day); } else { @@ -1611,27 +1717,27 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "homepage": // Set the new homepage URL as the summary text for the Homepage preference. - homepagePreference.setSummary(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value))); + homepagePreference.setSummary(sharedPreferences.getString("homepage", context.getString(R.string.homepage_default_value))); break; case "font_size": // Update the font size summary text. - fontSizePreference.setSummary(sharedPreferences.getString("font_size", getString(R.string.font_size_default_value)) + "%"); + fontSizePreference.setSummary(sharedPreferences.getString("font_size", context.getString(R.string.font_size_default_value)) + "%"); break; case "open_intents_in_new_tab": // Update the icon. if (sharedPreferences.getBoolean("open_intents_in_new_tab", true)) { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled_night); - } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled_day); + } else { + openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled_night); } } else { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled_night); - } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled_day); + } else { + openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled_night); } } break; @@ -1639,16 +1745,33 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "swipe_to_refresh": // Update the icon. if (sharedPreferences.getBoolean("swipe_to_refresh", true)) { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled_night); - } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled_day); + } else { + swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled_night); } } else { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled_day); + } else { swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled_night); + } + } + break; + + case "download_with_external_app": + // Update the icon. + if (sharedPreferences.getBoolean(context.getString(R.string.download_with_external_app_key), false)) { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled_day); } else { - swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled_day); + downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled_night); + } + } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { + downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled_day); + } else { + downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled_night); } } break; @@ -1656,40 +1779,40 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "scroll_app_bar": // Update the icon. if (sharedPreferences.getBoolean("scroll_app_bar", true)) { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled_night); - } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled_day); + } else { + scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled_night); } } else { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled_night); - } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled_day); + } else { + scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled_night); } } break; case "display_additional_app_bar_icons": // Update the icon. - if (sharedPreferences.getBoolean("display_additional_app_bar_icons", false)) { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled_night); - } else { + if (sharedPreferences.getBoolean(context.getString(R.string.display_additional_app_bar_icons_key), false)) { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled_day); + } else { + displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled_night); } } else { - if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { - displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled_night); - } else { + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) { displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled_day); + } else { + displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled_night); } } break; case "app_theme": // Get the new theme. - String newAppTheme = sharedPreferences.getString("app_theme", getString(R.string.app_theme_default_value)); + String newAppTheme = sharedPreferences.getString("app_theme", context.getString(R.string.app_theme_default_value)); // Update the system according to the new theme. A switch statement cannot be used because the theme entry values string array is not a compile time constant. if (newAppTheme.equals(appThemeEntryValuesStringArray[1])) { // The light theme is selected. @@ -1724,7 +1847,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { case "webview_theme": // Get the new WebView theme. - String newWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value)); + String newWebViewTheme = sharedPreferences.getString("webview_theme", context.getString(R.string.webview_theme_default_value)); // Define a new WebView theme entry number. int newWebViewThemeEntryNumber; @@ -1808,21 +1931,5 @@ public class SettingsFragment extends PreferenceFragmentCompat { break; } }; - - // Register the listener. - savedPreferences.registerOnSharedPreferenceChangeListener(preferencesListener); - } - - // It is necessary to re-register the listener on every resume or it will randomly stop working because apps can be paused and resumed at any time, even while running in the foreground. - @Override - public void onPause() { - super.onPause(); - savedPreferences.unregisterOnSharedPreferenceChangeListener(preferencesListener); - } - - @Override - public void onResume() { - super.onResume(); - savedPreferences.registerOnSharedPreferenceChangeListener(preferencesListener); } } \ No newline at end of file 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 22968adc..42cd1c7a 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java @@ -80,6 +80,7 @@ public class ImportExportDatabaseHelper { private static final String FONT_SIZE = "font_size"; private static final String OPEN_INTENTS_IN_NEW_TAB = "open_intents_in_new_tab"; private static final String SWIPE_TO_REFRESH = "swipe_to_refresh"; + private static final String DOWNLOAD_WITH_EXTERNAL_APP = "download_with_external_app"; 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"; @@ -344,6 +345,9 @@ public class ImportExportDatabaseHelper { // Copy the data from the old cookies columns to the new ones. importDatabase.execSQL("UPDATE " + DomainsDatabaseHelper.DOMAINS_TABLE + " SET " + DomainsDatabaseHelper.COOKIES + " = enablefirstpartycookies"); importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + COOKIES + " = first_party_cookies"); + + // Create the download with external app column. + importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + DOWNLOAD_WITH_EXTERNAL_APP + " BOOLEAN"); } } @@ -493,6 +497,7 @@ public class ImportExportDatabaseHelper { .putString(FONT_SIZE, importPreferencesCursor.getString(importPreferencesCursor.getColumnIndex(FONT_SIZE))) .putBoolean(OPEN_INTENTS_IN_NEW_TAB, importPreferencesCursor.getInt(importPreferencesCursor.getColumnIndex(OPEN_INTENTS_IN_NEW_TAB)) == 1) .putBoolean(SWIPE_TO_REFRESH, importPreferencesCursor.getInt(importPreferencesCursor.getColumnIndex(SWIPE_TO_REFRESH)) == 1) + .putBoolean(DOWNLOAD_WITH_EXTERNAL_APP, importPreferencesCursor.getInt(importPreferencesCursor.getColumnIndex(DOWNLOAD_WITH_EXTERNAL_APP)) == 1) .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))) @@ -660,6 +665,7 @@ public class ImportExportDatabaseHelper { FONT_SIZE + " TEXT, " + OPEN_INTENTS_IN_NEW_TAB + " BOOLEAN, " + SWIPE_TO_REFRESH + " BOOLEAN, " + + DOWNLOAD_WITH_EXTERNAL_APP + " BOOLEAN, " + SCROLL_APP_BAR + " BOOLEAN, " + DISPLAY_ADDITIONAL_APP_BAR_ICONS + " BOOLEAN, " + APP_THEME + " TEXT, " + @@ -709,6 +715,7 @@ public class ImportExportDatabaseHelper { preferencesContentValues.put(FONT_SIZE, sharedPreferences.getString(FONT_SIZE, context.getString(R.string.font_size_default_value))); preferencesContentValues.put(OPEN_INTENTS_IN_NEW_TAB, sharedPreferences.getBoolean(OPEN_INTENTS_IN_NEW_TAB, true)); preferencesContentValues.put(SWIPE_TO_REFRESH, sharedPreferences.getBoolean(SWIPE_TO_REFRESH, true)); + preferencesContentValues.put(DOWNLOAD_WITH_EXTERNAL_APP, sharedPreferences.getBoolean(DOWNLOAD_WITH_EXTERNAL_APP, false)); 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))); diff --git a/app/src/main/res/drawable/download_with_external_app_disabled_day.xml b/app/src/main/res/drawable/download_with_external_app_disabled_day.xml new file mode 100644 index 00000000..de9ffcd8 --- /dev/null +++ b/app/src/main/res/drawable/download_with_external_app_disabled_day.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/download_with_external_app_disabled_night.xml b/app/src/main/res/drawable/download_with_external_app_disabled_night.xml new file mode 100644 index 00000000..38e44bbd --- /dev/null +++ b/app/src/main/res/drawable/download_with_external_app_disabled_night.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/clear_and_exit.xml b/app/src/main/res/drawable/download_with_external_app_enabled_day.xml similarity index 100% rename from app/src/main/res/drawable/clear_and_exit.xml rename to app/src/main/res/drawable/download_with_external_app_enabled_day.xml index 1c64ee9d..971eec77 100644 --- a/app/src/main/res/drawable/clear_and_exit.xml +++ b/app/src/main/res/drawable/download_with_external_app_enabled_day.xml @@ -6,9 +6,9 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:height="24dp" + android:width="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" - android:width="24dp" android:autoMirrored="true" tools:ignore="VectorRaster" > diff --git a/app/src/main/res/drawable/download_with_external_app_enabled_night.xml b/app/src/main/res/drawable/download_with_external_app_enabled_night.xml new file mode 100644 index 00000000..78b6d66d --- /dev/null +++ b/app/src/main/res/drawable/download_with_external_app_enabled_night.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/webview_navigation_menu.xml b/app/src/main/res/menu/webview_navigation_menu.xml index fac6f0b4..cc939f24 100644 --- a/app/src/main/res/menu/webview_navigation_menu.xml +++ b/app/src/main/res/menu/webview_navigation_menu.xml @@ -24,7 +24,7 @@ diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index dc7c66bf..11f3539c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -232,6 +232,7 @@ Lesezeichen Lesezeichen-Übersicht + Das Lesezeichen wurde in einem Tab im Hintergrund geöffnet. Lesezeichen erstellen Ordner erstellen Symbol für das aktuelle Lesezeichen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 2f29a254..8ad3703d 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -229,6 +229,7 @@ Favoritos Vista de base de datos + El favorito se abrió en una pestaña de fondo. Crear favorito Crear carpeta Icono de favorito actual diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index f21ca42d..0cea7419 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -228,6 +228,7 @@ Segnalibri Vista Database + Il segnalibro è stato aperto in una scheda in background. Crea Segnalibro Crea Cartella Icona Segnalibro diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 09a75250..5ece332c 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -225,6 +225,7 @@ Закладки Просмотр базы данных + Закладка была открыта в фоновой вкладке. Создание закладки Создание папки Текущий значок закладки diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2728f652..f45b434d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -620,6 +620,8 @@ Intents are links sent from other apps. Swipe to refresh Some websites don’t work well if swipe to refresh is enabled. + Download with external app + Use an external app to download files. Scroll the app bar Scroll the app bar off the top of the screen when the WebView scrolls down. Display additional app bar icons @@ -655,6 +657,7 @@ cookies allow_screenshots clear_logcat + download_with_external_app display_additional_app_bar_icons diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 9291837e..5d4e80cc 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -273,6 +273,12 @@ android:summary="@string/swipe_to_refresh_summary" android:defaultValue="true" /> + +