2 * Copyright © 2016-2022 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
6 * Privacy Browser Android is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser Android is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser Android. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments;
22 import android.annotation.SuppressLint;
23 import android.app.Activity;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.SharedPreferences;
27 import android.content.res.Configuration;
28 import android.content.res.Resources;
29 import android.os.Build;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.os.Looper;
33 import android.view.LayoutInflater;
34 import android.view.View;
35 import android.webkit.WebView;
36 import android.widget.ArrayAdapter;
38 import androidx.appcompat.app.AppCompatDelegate;
39 import androidx.preference.Preference;
40 import androidx.preference.PreferenceCategory;
41 import androidx.preference.PreferenceFragmentCompat;
43 import com.stoutner.privacybrowser.R;
44 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
45 import com.stoutner.privacybrowser.helpers.ProxyHelper;
47 import java.util.Objects;
49 public class SettingsFragment extends PreferenceFragmentCompat {
50 // Declare the class variables.
51 private int currentThemeStatus;
52 private String defaultUserAgent;
53 private ArrayAdapter<CharSequence> userAgentNamesArray;
54 private String[] translatedUserAgentNamesArray;
55 private String[] userAgentDataArray;
56 private String[] appThemeEntriesStringArray;
57 private String[] appThemeEntryValuesStringArray;
58 private String[] webViewThemeEntriesStringArray;
59 private String[] webViewThemeEntryValuesStringArray;
60 private SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener;
62 // Declare the class views.
63 private Preference javaScriptPreference;
64 private Preference cookiesPreference;
65 private Preference domStoragePreference;
66 private Preference formDataPreference; // The form data preference can be removed once the minimum API >= 26.
67 private Preference userAgentPreference;
68 private Preference customUserAgentPreference;
69 private Preference xRequestedWithHeaderPreference;
70 private Preference incognitoModePreference;
71 private Preference allowScreenshotsPreference;
72 private Preference easyListPreference;
73 private Preference easyPrivacyPreference;
74 private Preference fanboyAnnoyanceListPreference;
75 private Preference fanboySocialBlockingListPreference;
76 private Preference ultraListPreference;
77 private Preference ultraPrivacyPreference;
78 private Preference blockAllThirdPartyRequestsPreference;
79 private Preference trackingQueriesPreference;
80 private Preference ampRedirectsPreference;
81 private Preference searchPreference;
82 private Preference searchCustomURLPreference;
83 private Preference proxyPreference;
84 private Preference proxyCustomUrlPreference;
85 private Preference fullScreenBrowsingModePreference;
86 private Preference hideAppBarPreference;
87 private Preference clearEverythingPreference;
88 private Preference clearCookiesPreference;
89 private Preference clearDomStoragePreference;
90 private Preference clearFormDataPreference; // The clear form data preference can be removed once the minimum API >= 26.
91 private Preference clearLogcatPreference;
92 private Preference clearCachePreference;
93 private Preference homepagePreference;
94 private Preference fontSizePreference;
95 private Preference openIntentsInNewTabPreference;
96 private Preference swipeToRefreshPreference;
97 private Preference downloadWithExternalAppPreference;
98 private Preference scrollAppBarPreference;
99 private Preference bottomAppBarPreference;
100 private Preference displayAdditionalAppBarIconsPreference;
101 private Preference appThemePreference;
102 private Preference webViewThemePreference;
103 private Preference wideViewportPreference;
104 private Preference displayWebpageImagesPreference;
107 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
108 // Load the preferences from the XML file.
109 setPreferencesFromResource(R.xml.preferences, rootKey);
111 // Get a handle for the activity.
112 Activity activity = getActivity();
114 // Remove the lint warning below that `getApplicationContext()` might produce a null pointer exception.
115 assert activity != null;
117 // Get a handle for the resources.
118 Resources resources = getResources();
120 // Get the current theme status.
121 currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
123 // Get a handle for the shared preferences.
124 SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
126 // Remove the incorrect warning below that the shared preferences might be null.
127 assert sharedPreferences != null;
129 // Get handles for the preferences.
130 javaScriptPreference = findPreference("javascript");
131 cookiesPreference = findPreference(getString(R.string.cookies_key));
132 domStoragePreference = findPreference("dom_storage");
133 formDataPreference = findPreference("save_form_data"); // The form data preference can be removed once the minimum API >= 26.
134 userAgentPreference = findPreference("user_agent");
135 customUserAgentPreference = findPreference("custom_user_agent");
136 xRequestedWithHeaderPreference = findPreference(getString(R.string.x_requested_with_header_key));
137 incognitoModePreference = findPreference("incognito_mode");
138 allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key));
139 easyListPreference = findPreference("easylist");
140 easyPrivacyPreference = findPreference("easyprivacy");
141 fanboyAnnoyanceListPreference = findPreference("fanboys_annoyance_list");
142 fanboySocialBlockingListPreference = findPreference("fanboys_social_blocking_list");
143 ultraListPreference = findPreference("ultralist");
144 ultraPrivacyPreference = findPreference("ultraprivacy");
145 blockAllThirdPartyRequestsPreference = findPreference("block_all_third_party_requests");
146 trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key));
147 ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key));
148 searchPreference = findPreference("search");
149 searchCustomURLPreference = findPreference("search_custom_url");
150 proxyPreference = findPreference("proxy");
151 proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key));
152 fullScreenBrowsingModePreference = findPreference("full_screen_browsing_mode");
153 hideAppBarPreference = findPreference("hide_app_bar");
154 clearEverythingPreference = findPreference("clear_everything");
155 clearCookiesPreference = findPreference("clear_cookies");
156 clearDomStoragePreference = findPreference("clear_dom_storage");
157 clearFormDataPreference = findPreference("clear_form_data"); // The clear form data preference can be removed once the minimum API >= 26.
158 clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key));
159 clearCachePreference = findPreference("clear_cache");
160 homepagePreference = findPreference("homepage");
161 fontSizePreference = findPreference("font_size");
162 openIntentsInNewTabPreference = findPreference("open_intents_in_new_tab");
163 swipeToRefreshPreference = findPreference("swipe_to_refresh");
164 downloadWithExternalAppPreference = findPreference(getString(R.string.download_with_external_app_key));
165 scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key));
166 bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key));
167 displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key));
168 appThemePreference = findPreference("app_theme");
169 webViewThemePreference = findPreference("webview_theme");
170 wideViewportPreference = findPreference("wide_viewport");
171 displayWebpageImagesPreference = findPreference("display_webpage_images");
173 // Remove the lint warnings below that the preferences might be null.
174 assert javaScriptPreference != null;
175 assert cookiesPreference != null;
176 assert domStoragePreference != null;
177 assert formDataPreference != null;
178 assert userAgentPreference != null;
179 assert customUserAgentPreference != null;
180 assert xRequestedWithHeaderPreference != null;
181 assert incognitoModePreference != null;
182 assert allowScreenshotsPreference != null;
183 assert easyListPreference != null;
184 assert easyPrivacyPreference != null;
185 assert fanboyAnnoyanceListPreference != null;
186 assert fanboySocialBlockingListPreference != null;
187 assert ultraListPreference != null;
188 assert ultraPrivacyPreference != null;
189 assert blockAllThirdPartyRequestsPreference != null;
190 assert trackingQueriesPreference != null;
191 assert ampRedirectsPreference != null;
192 assert searchPreference != null;
193 assert searchCustomURLPreference != null;
194 assert proxyPreference != null;
195 assert proxyCustomUrlPreference != null;
196 assert fullScreenBrowsingModePreference != null;
197 assert hideAppBarPreference != null;
198 assert clearEverythingPreference != null;
199 assert clearCookiesPreference != null;
200 assert clearDomStoragePreference != null;
201 assert clearFormDataPreference != null;
202 assert clearLogcatPreference != null;
203 assert clearCachePreference != null;
204 assert homepagePreference != null;
205 assert fontSizePreference != null;
206 assert openIntentsInNewTabPreference != null;
207 assert swipeToRefreshPreference != null;
208 assert downloadWithExternalAppPreference != null;
209 assert scrollAppBarPreference != null;
210 assert bottomAppBarPreference != null;
211 assert displayAdditionalAppBarIconsPreference != null;
212 assert appThemePreference != null;
213 assert webViewThemePreference != null;
214 assert wideViewportPreference != null;
215 assert displayWebpageImagesPreference != null;
217 // Set the preference dependencies.
218 hideAppBarPreference.setDependency("full_screen_browsing_mode");
219 domStoragePreference.setDependency("javascript");
221 // Get strings from the preferences.
222 String userAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
223 String searchString = sharedPreferences.getString("search", getString(R.string.search_default_value));
224 String proxyString = sharedPreferences.getString("proxy", getString(R.string.proxy_default_value));
226 // Get booleans that are used in multiple places from the preferences.
227 boolean javaScriptEnabled = sharedPreferences.getBoolean("javascript", false);
228 boolean fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboys_annoyance_list", true);
229 boolean fanboySocialBlockingEnabled = sharedPreferences.getBoolean("fanboys_social_blocking_list", true);
230 boolean fullScreenBrowsingMode = sharedPreferences.getBoolean("full_screen_browsing_mode", false);
231 boolean clearEverything = sharedPreferences.getBoolean("clear_everything", true);
233 // Remove the form data preferences if the API is >= 26 as they no longer do anything.
234 if (Build.VERSION.SDK_INT >= 26) {
235 // Get handles for the categories.
236 PreferenceCategory privacyCategory = findPreference("privacy");
237 PreferenceCategory clearAndExitCategory = findPreference("clear_and_exit");
239 // Remove the incorrect lint warnings below that the preference categories might be null.
240 assert privacyCategory != null;
241 assert clearAndExitCategory != null;
243 // Remove the form data preferences.
244 privacyCategory.removePreference(formDataPreference);
245 clearAndExitCategory.removePreference(clearFormDataPreference);
248 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
249 fanboySocialBlockingListPreference.setEnabled(!fanboyAnnoyanceListEnabled);
252 // Inflate a WebView to get the default user agent.
253 LayoutInflater inflater = getActivity().getLayoutInflater();
255 // `@SuppressLint("InflateParams")` removes the warning about using `null` as the `ViewGroup`, which in this case makes sense because the `bare_webview` will not be displayed.
256 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
258 // Get a handle for a bare WebView.
259 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
261 // Get the default user agent.
262 defaultUserAgent = bareWebView.getSettings().getUserAgentString();
264 // Get the user agent arrays.
265 userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item);
266 translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names);
267 userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
269 // Get the array position of the user agent name.
270 int userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName);
272 // Populate the user agent summary.
273 switch (userAgentArrayPosition) {
274 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The user agent name is not on the canonical list.
275 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. Use the current user agent entry name as the summary.
276 userAgentPreference.setSummary(userAgentName);
279 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
280 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
281 userAgentPreference.setSummary(translatedUserAgentNamesArray[userAgentArrayPosition] + ":\n" + defaultUserAgent);
284 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
285 // Set the summary text.
286 userAgentPreference.setSummary(R.string.custom_user_agent);
290 // Get the user agent summary from the user agent data array.
291 userAgentPreference.setSummary(translatedUserAgentNamesArray[userAgentArrayPosition] + ":\n" + userAgentDataArray[userAgentArrayPosition]);
294 // Set the summary text for the custom user agent preference.
295 customUserAgentPreference.setSummary(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value)));
297 // Only enable the custom user agent preference if the user agent is set to `Custom`.
298 customUserAgentPreference.setEnabled(Objects.equals(userAgentPreference.getSummary(), getString(R.string.custom_user_agent)));
300 // Set the search URL as the summary text for the search preference when the preference screen is loaded.
301 if (searchString.equals("Custom URL")) {
302 // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
303 searchPreference.setSummary(R.string.custom_url);
305 // Set the array value as the summary text.
306 searchPreference.setSummary(searchString);
309 // Set the summary text for the search custom URL (the default is `""`).
310 searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", getString(R.string.search_custom_url_default_value)));
312 // Only enable the search custom URL preference if the search is set to `Custom URL`.
313 searchCustomURLPreference.setEnabled(searchString.equals("Custom URL"));
316 // Set the summary text for the proxy preference when the preference screen is loaded.
317 switch (proxyString) {
318 case ProxyHelper.NONE:
319 proxyPreference.setSummary(getString(R.string.no_proxy_enabled));
322 case ProxyHelper.TOR:
323 proxyPreference.setSummary(getString(R.string.tor_enabled));
326 case ProxyHelper.I2P:
327 proxyPreference.setSummary(getString(R.string.i2p_enabled));
330 case ProxyHelper.CUSTOM:
331 proxyPreference.setSummary(getString(R.string.custom_proxy));
335 // Set the summary text for the custom proxy URL.
336 proxyCustomUrlPreference.setSummary(sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value)));
338 // Only enable the custom proxy URL if a custom proxy is selected.
339 proxyCustomUrlPreference.setEnabled(proxyString.equals(ProxyHelper.CUSTOM));
342 // Set the status of the clear and exit preferences.
343 clearCookiesPreference.setEnabled(!clearEverything);
344 clearDomStoragePreference.setEnabled(!clearEverything);
345 clearFormDataPreference.setEnabled(!clearEverything); // The form data line can be removed once the minimum API is >= 26.
346 clearLogcatPreference.setEnabled(!clearEverything);
347 clearCachePreference.setEnabled(!clearEverything);
350 // Set the homepage URL as the summary text for the homepage preference.
351 homepagePreference.setSummary(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value)));
354 // Set the font size as the summary text for the preference.
355 fontSizePreference.setSummary(sharedPreferences.getString("font_size", getString(R.string.font_size_default_value)) + "%");
358 // Get the app theme string arrays.
359 appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries);
360 appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values);
362 // Get the current app theme.
363 String currentAppTheme = sharedPreferences.getString("app_theme", getString(R.string.app_theme_default_value));
365 // Define an app theme entry number.
366 int appThemeEntryNumber;
368 // Get the app theme entry number that matches the current app theme. A switch statement cannot be used because the theme entry values string array is not a compile time constant.
369 if (currentAppTheme.equals(appThemeEntryValuesStringArray[1])) { // The light theme is selected.
370 // Store the app theme entry number.
371 appThemeEntryNumber = 1;
372 } else if (currentAppTheme.equals(appThemeEntryValuesStringArray[2])) { // The dark theme is selected.
373 // Store the app theme entry number.
374 appThemeEntryNumber = 2;
375 } else { // The system default theme is selected.
376 // Store the app theme entry number.
377 appThemeEntryNumber = 0;
380 // Set the current theme as the summary text for the preference.
381 appThemePreference.setSummary(appThemeEntriesStringArray[appThemeEntryNumber]);
384 // Get the WebView theme string arrays.
385 webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries);
386 webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values);
388 // Get the current WebView theme.
389 String currentWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value));
391 // Define a WebView theme entry number.
392 int webViewThemeEntryNumber;
394 // 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.
395 if (currentWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected.
396 // Store the WebView theme entry number.
397 webViewThemeEntryNumber = 1;
398 } else if (currentWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected.
399 // Store the WebView theme entry number.
400 webViewThemeEntryNumber = 2;
401 } else { // The system default theme is selected.
402 // Store the WebView theme entry number.
403 webViewThemeEntryNumber = 0;
406 // Set the current theme as the summary text for the preference.
407 webViewThemePreference.setSummary(webViewThemeEntriesStringArray[webViewThemeEntryNumber]);
410 // Set the JavaScript icon.
411 if (javaScriptEnabled) {
412 javaScriptPreference.setIcon(R.drawable.javascript_enabled);
414 javaScriptPreference.setIcon(R.drawable.privacy_mode);
417 // Set the cookies icon.
418 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false)) {
419 cookiesPreference.setIcon(R.drawable.cookies_enabled);
421 cookiesPreference.setIcon(R.drawable.cookies_disabled);
424 // Set the DOM storage icon.
425 if (javaScriptEnabled) { // The preference is enabled.
426 if (sharedPreferences.getBoolean("dom_storage", false)) { // DOM storage is enabled.
427 domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
428 } else { // DOM storage is disabled.
429 domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
431 } else { // The preference is disabled. The icon should be ghosted.
432 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
435 // Set the save form data icon if API < 26. Save form data has no effect on API >= 26.
436 if (Build.VERSION.SDK_INT < 26) {
437 if (sharedPreferences.getBoolean("save_form_data", false))
438 formDataPreference.setIcon(R.drawable.form_data_enabled);
440 formDataPreference.setIcon(R.drawable.form_data_disabled);
443 // Set the custom user agent icon.
444 if (customUserAgentPreference.isEnabled())
445 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
447 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
449 // Set the X-Requested With header icon.
450 if (sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true))
451 xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_enabled);
453 xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_disabled);
455 // Set the incognito mode icon.
456 if (sharedPreferences.getBoolean("incognito_mode", false))
457 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
459 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
461 // Set the allow screenshots icon.
462 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
463 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled);
465 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled);
467 // Set the EasyList icon.
468 if (sharedPreferences.getBoolean("easylist", true))
469 easyListPreference.setIcon(R.drawable.block_ads_enabled);
471 easyListPreference.setIcon(R.drawable.block_ads_disabled);
473 // Set the EasyPrivacy icon.
474 if (sharedPreferences.getBoolean("easyprivacy", true))
475 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
477 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
479 // Set the Fanboy lists icons.
480 if (fanboyAnnoyanceListEnabled) {
481 // Set the Fanboy annoyance list icon.
482 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled);
484 // Set the Fanboy social blocking list icon.
485 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted);
487 // Set the Fanboy annoyance list icon.
488 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled);
490 // Set the Fanboy social blocking list icon.
491 if (fanboySocialBlockingEnabled) {
492 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled);
494 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled);
498 // Set the UltraList icon.
499 if (sharedPreferences.getBoolean("ultralist", true)){
500 ultraListPreference.setIcon(R.drawable.block_ads_enabled);
502 ultraListPreference.setIcon(R.drawable.block_ads_disabled);
505 // Set the UltraPrivacy icon.
506 if (sharedPreferences.getBoolean("ultraprivacy", true)) {
507 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
509 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
512 // Set the block all third-party requests icon.
513 if (sharedPreferences.getBoolean("block_all_third_party_requests", false)) {
514 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled);
516 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled);
519 // Set the Tracking Queries icon.
520 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true)) {
521 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled);
523 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled);
526 // Set the AMP Redirects icon.
527 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true)) {
528 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled);
530 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled);
533 // Set the search custom URL icon.
534 if (searchCustomURLPreference.isEnabled()) {
535 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled);
537 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted);
540 // Set the Proxy icons according to the theme and status.
541 if (proxyString.equals(ProxyHelper.NONE)) { // Proxying is disabled.
542 // Set the main proxy icon to be disabled.
543 proxyPreference.setIcon(R.drawable.proxy_disabled);
545 // Set the custom proxy URL icon to be ghosted.
546 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
547 } else { // Proxying is enabled.
548 // Set the main proxy icon to be enabled.
549 proxyPreference.setIcon(R.drawable.proxy_enabled);
551 // Set the custom proxy URL icon according to its status.
552 if (proxyCustomUrlPreference.isEnabled()) {
553 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled);
555 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
559 // Set the full screen browsing mode icons.
560 if (fullScreenBrowsingMode) { // Full screen browsing mode is enabled.
561 // Set the full screen browsing mode preference icon.
562 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
564 // Set the hide app bar icon.
565 if (sharedPreferences.getBoolean("hide_app_bar", true)) {
566 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
568 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
570 } else { // Full screen browsing mode is disabled.
572 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
573 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted);
576 // Set the clear everything preference icon.
577 if (clearEverything) {
578 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
580 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
583 // Set the clear cookies preference icon.
584 if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) {
585 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
587 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
590 // Set the clear DOM storage preference icon.
591 if (clearEverything || sharedPreferences.getBoolean("clear_dom_storage", true)) {
592 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
594 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
597 // Set the clear form data preference icon if the API < 26. It has no effect on newer versions of Android.
598 if (Build.VERSION.SDK_INT < 26) {
599 if (clearEverything || sharedPreferences.getBoolean("clear_form_data", true)) {
600 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
602 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
606 // Set the clear logcat preference icon.
607 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true)) {
608 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
610 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled);
613 // Set the clear cache preference icon.
614 if (clearEverything || sharedPreferences.getBoolean("clear_cache", true)) {
615 clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
617 clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
620 // Set the open intents in new tab preference icon.
621 if (sharedPreferences.getBoolean("open_intents_in_new_tab", true)) {
622 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled);
624 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled);
627 // Set the swipe to refresh preference icon.
628 if (sharedPreferences.getBoolean("swipe_to_refresh", true)) {
629 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
631 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
634 // Set the download with external app preference icon.
635 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false)) {
636 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled);
638 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled);
641 // Set the scroll app bar preference icon.
642 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true)) {
643 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled);
645 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled);
648 // Set the bottom app bar preference icon.
649 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
650 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled);
652 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled);
655 // Set the display additional app bar icons preference icon.
656 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false)) {
657 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
659 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
662 // Set the WebView theme preference icon.
663 switch (webViewThemeEntryNumber) {
664 case 0: // The system default WebView theme is selected.
665 // Set the icon according to the app theme.
666 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
667 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
669 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
673 case 1: // The light WebView theme is selected.
675 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
678 case 2: // The dark WebView theme is selected.
680 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
684 // Set the wide viewport preference icon.
685 if (sharedPreferences.getBoolean("wide_viewport", true)) {
686 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled);
688 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled);
691 // Set the display webpage images preference icon.
692 if (sharedPreferences.getBoolean("display_webpage_images", true)) {
693 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
695 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
699 // The listener should be unregistered when the app is paused.
701 public void onPause() {
702 // Run the default commands.
705 // Get a handle for the shared preferences.
706 SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
708 // Remove the incorrect lint warning below that the shared preferences might be null.
709 assert sharedPreferences != null;
711 // Unregister the shared preference listener.
712 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
715 // The listener should be re-registered when the app is resumed.
717 public void onResume() {
718 // Run the default commands.
721 // Get a new shared preference change listener.
722 sharedPreferenceChangeListener = getSharedPreferenceChangeListener(requireContext());
724 // Get a handle for the shared preferences.
725 SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
727 // Remove the incorrect lint warning below that the shared preferences might be null.
728 assert sharedPreferences != null;
730 // Re-register the shared preference listener.
731 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
734 // 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.
735 // This can be removed at some future point, perhaps after the switch to PreferenceScreenCompat. It isn't an issue in Privacy Cell.
736 private SharedPreferences.OnSharedPreferenceChangeListener getSharedPreferenceChangeListener(Context context) {
737 // Return the shared preference change listener.
738 return (SharedPreferences sharedPreferences, String key) -> {
741 // Update the icons and the DOM storage preference status.
742 if (sharedPreferences.getBoolean("javascript", false)) { // The JavaScript preference is enabled.
743 // Update the icon for the JavaScript preference.
744 javaScriptPreference.setIcon(R.drawable.javascript_enabled);
746 // Update the status of the DOM storage preference.
747 domStoragePreference.setEnabled(true);
749 // Update the icon for the DOM storage preference.
750 if (sharedPreferences.getBoolean("dom_storage", false)) {
751 domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
753 domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
755 } else { // The JavaScript preference is disabled.
756 // Update the icon for the JavaScript preference.
757 javaScriptPreference.setIcon(R.drawable.privacy_mode);
759 // Update the status of the DOM storage preference.
760 domStoragePreference.setEnabled(false);
762 // Set the icon for DOM storage preference to be ghosted.
763 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
769 if (sharedPreferences.getBoolean(context.getString(R.string.cookies_key), false)) {
770 cookiesPreference.setIcon(R.drawable.cookies_enabled);
772 cookiesPreference.setIcon(R.drawable.cookies_disabled);
778 if (sharedPreferences.getBoolean("dom_storage", false)) {
779 domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
781 domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
785 // Save form data can be removed once the minimum API >= 26.
786 case "save_form_data":
788 if (sharedPreferences.getBoolean("save_form_data", false)) {
789 formDataPreference.setIcon(R.drawable.form_data_enabled);
791 formDataPreference.setIcon(R.drawable.form_data_disabled);
796 // Get the new user agent name.
797 String newUserAgentName = sharedPreferences.getString("user_agent", context.getString(R.string.user_agent_default_value));
799 // Get the array position for the new user agent name.
800 int newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName);
802 // Get the translated new user agent name.
803 String translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition];
805 // Populate the user agent summary.
806 switch (newUserAgentArrayPosition) {
807 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
808 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
809 userAgentPreference.setSummary(translatedNewUserAgentName + ":\n" + defaultUserAgent);
811 // Disable the custom user agent preference.
812 customUserAgentPreference.setEnabled(false);
814 // Set the custom user agent preference icon.
815 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
818 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
819 // Set the summary text.
820 userAgentPreference.setSummary(R.string.custom_user_agent);
822 // Enable the custom user agent preference.
823 customUserAgentPreference.setEnabled(true);
825 // Set the custom user agent preference icon.
826 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
830 // Get the user agent summary from the user agent data array.
831 userAgentPreference.setSummary(translatedNewUserAgentName + ":\n" + userAgentDataArray[newUserAgentArrayPosition]);
833 // Disable the custom user agent preference.
834 customUserAgentPreference.setEnabled(false);
836 // Set the custom user agent preference icon.
837 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
841 case "custom_user_agent":
842 // Set the new custom user agent as the summary text for the preference.
843 customUserAgentPreference.setSummary(sharedPreferences.getString("custom_user_agent", context.getString(R.string.custom_user_agent_default_value)));
846 case "x_requested_with_header":
848 if (sharedPreferences.getBoolean(context.getString(R.string.x_requested_with_header_key), true))
849 xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_enabled);
851 xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_disabled);
853 // Restart Privacy Browser.
854 restartPrivacyBrowser();
857 case "incognito_mode":
859 if (sharedPreferences.getBoolean("incognito_mode", false))
860 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
862 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
865 case "allow_screenshots":
867 if (sharedPreferences.getBoolean(context.getString(R.string.allow_screenshots_key), false))
868 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled);
870 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled);
872 // Restart Privacy Browser.
873 restartPrivacyBrowser();
878 if (sharedPreferences.getBoolean("easylist", true))
879 easyListPreference.setIcon(R.drawable.block_ads_enabled);
881 easyListPreference.setIcon(R.drawable.block_ads_disabled);
886 if (sharedPreferences.getBoolean("easyprivacy", true))
887 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
889 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
892 case "fanboys_annoyance_list":
893 boolean currentFanboyAnnoyanceList = sharedPreferences.getBoolean("fanboys_annoyance_list", true);
894 boolean currentFanboySocialBlockingList = sharedPreferences.getBoolean("fanboys_social_blocking_list", true);
896 // Update the Fanboy icons.
897 if (currentFanboyAnnoyanceList) { // Fanboy's annoyance list is enabled.
898 // Update the Fanboy's annoyance list icon.
899 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled);
901 // Update the Fanboy's social blocking list icon.
902 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted);
903 } else { // Fanboy's annoyance list is disabled.
904 // Update the Fanboy's annoyance list icon.
905 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled);
907 // Update the Fanboy's social blocking list icon.
908 if (currentFanboySocialBlockingList) {
909 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled);
911 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled);
915 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
916 fanboySocialBlockingListPreference.setEnabled(!currentFanboyAnnoyanceList);
919 case "fanboys_social_blocking_list":
921 if (sharedPreferences.getBoolean("fanboys_social_blocking_list", true)) {
922 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled);
924 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled);
930 if (sharedPreferences.getBoolean("ultralist", true)) {
931 ultraListPreference.setIcon(R.drawable.block_ads_enabled);
933 ultraListPreference.setIcon(R.drawable.block_ads_disabled);
939 if (sharedPreferences.getBoolean("ultraprivacy", true)) {
940 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
942 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
946 case "block_all_third_party_requests":
948 if (sharedPreferences.getBoolean("block_all_third_party_requests", false)) {
949 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled);
951 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled);
955 case "tracking_queries":
957 if (sharedPreferences.getBoolean(context.getString(R.string.tracking_queries_key), true)) {
958 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled);
960 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled);
964 case "amp_redirects":
966 if (sharedPreferences.getBoolean(context.getString(R.string.amp_redirects_key), true)) {
967 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled);
969 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled);
974 // Store the new search string.
975 String newSearchString = sharedPreferences.getString("search", context.getString(R.string.search_default_value));
977 // Update the search and search custom URL preferences.
978 if (newSearchString.equals("Custom URL")) { // `Custom URL` is selected.
979 // Set the summary text to `R.string.custom_url`, which is translated.
980 searchPreference.setSummary(R.string.custom_url);
982 // Enable the search custom URL preference.
983 searchCustomURLPreference.setEnabled(true);
985 // Set the search custom URL preference icon.
986 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled);
987 } else { // `Custom URL` is not selected.
988 // Set the summary text to `newSearchString`.
989 searchPreference.setSummary(newSearchString);
991 // Disable `searchCustomURLPreference`.
992 searchCustomURLPreference.setEnabled(false);
994 // Set the search custom URL preference icon.
995 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted);
999 case "search_custom_url":
1000 // Set the new search custom URL as the summary text for the preference.
1001 searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", context.getString(R.string.search_custom_url_default_value)));
1005 // Get current proxy string.
1006 String currentProxyString = sharedPreferences.getString("proxy", context.getString(R.string.proxy_default_value));
1008 // Update the summary text for the proxy preference.
1009 switch (currentProxyString) {
1010 case ProxyHelper.NONE:
1011 proxyPreference.setSummary(context.getString(R.string.no_proxy_enabled));
1014 case ProxyHelper.TOR:
1015 proxyPreference.setSummary(context.getString(R.string.tor_enabled));
1018 case ProxyHelper.I2P:
1019 proxyPreference.setSummary(context.getString(R.string.i2p_enabled));
1022 case ProxyHelper.CUSTOM:
1023 proxyPreference.setSummary(context.getString(R.string.custom_proxy));
1027 // Update the status of the custom URL preference.
1028 proxyCustomUrlPreference.setEnabled(currentProxyString.equals(ProxyHelper.CUSTOM));
1030 // Update the icons.
1031 if (currentProxyString.equals(ProxyHelper.NONE)) { // Proxying is disabled.
1032 // Set the main proxy icon to be disabled
1033 proxyPreference.setIcon(R.drawable.proxy_disabled);
1035 // Set the custom proxy URL icon to be ghosted.
1036 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
1037 } else { // Proxying is enabled.
1038 // Set the main proxy icon to be enabled.
1039 proxyPreference.setIcon(R.drawable.proxy_enabled);
1041 /// Set the custom proxy URL icon according to its status.
1042 if (proxyCustomUrlPreference.isEnabled()) {
1043 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled);
1045 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
1050 case "proxy_custom_url":
1051 // Set the summary text for the proxy custom URL.
1052 proxyCustomUrlPreference.setSummary(sharedPreferences.getString(context.getString(R.string.proxy_custom_url_key), context.getString(R.string.proxy_custom_url_default_value)));
1055 case "full_screen_browsing_mode":
1056 if (sharedPreferences.getBoolean("full_screen_browsing_mode", false)) { // Full screen browsing is enabled.
1057 // Set the full screen browsing mode preference icon.
1058 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
1060 // Set the hide app bar preference icon.
1061 if (sharedPreferences.getBoolean("hide_app_bar", true)) {
1062 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1064 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1066 } else { // Full screen browsing is disabled.
1067 // Update the icons.
1068 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
1069 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted);
1073 case "hide_app_bar":
1075 if (sharedPreferences.getBoolean("hide_app_bar", true)) {
1076 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1077 } else { // Hide app bar is disabled.
1078 // Set the icon according to the theme.
1079 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1083 case "clear_everything":
1084 // Store the new clear everything status
1085 boolean newClearEverythingBoolean = sharedPreferences.getBoolean("clear_everything", true);
1087 // Update the status of the clear and exit preferences.
1088 clearCookiesPreference.setEnabled(!newClearEverythingBoolean);
1089 clearDomStoragePreference.setEnabled(!newClearEverythingBoolean);
1090 clearFormDataPreference.setEnabled(!newClearEverythingBoolean); // This line can be removed once the minimum API >= 26.
1091 clearLogcatPreference.setEnabled(!newClearEverythingBoolean);
1092 clearCachePreference.setEnabled(!newClearEverythingBoolean);
1094 // Update the clear everything preference icon.
1095 if (newClearEverythingBoolean) {
1096 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
1098 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
1101 // Update the clear cookies preference icon.
1102 if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cookies", true)) {
1103 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
1105 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
1108 // Update the clear dom storage preference icon.
1109 if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_dom_storage", true)) {
1110 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
1112 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
1115 // Update the clear form data preference icon if the API < 26.
1116 if (Build.VERSION.SDK_INT < 26) {
1117 if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_form_data", true)) {
1118 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
1120 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
1124 // Update the clear logcat preference icon.
1125 if (newClearEverythingBoolean || sharedPreferences.getBoolean(context.getString(R.string.clear_logcat_key), true)) {
1126 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
1128 clearLogcatPreference.setIcon(R.drawable.clear_cache_disabled);
1131 // Update the clear cache preference icon.
1132 if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cache", true)) {
1133 clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
1135 clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
1139 case "clear_cookies":
1141 if (sharedPreferences.getBoolean("clear_cookies", true)) {
1142 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
1144 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
1148 case "clear_dom_storage":
1150 if (sharedPreferences.getBoolean("clear_dom_storage", true)) {
1151 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
1153 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
1157 // This section can be removed once the minimum API >= 26.
1158 case "clear_form_data":
1160 if (sharedPreferences.getBoolean("clear_form_data", true)) {
1161 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
1163 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
1167 case "clear_logcat":
1169 if (sharedPreferences.getBoolean(context.getString(R.string.clear_logcat_key), true)) {
1170 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
1172 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled);
1178 if (sharedPreferences.getBoolean("clear_cache", true)) {
1179 clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
1181 clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
1186 // Set the new homepage URL as the summary text for the Homepage preference.
1187 homepagePreference.setSummary(sharedPreferences.getString("homepage", context.getString(R.string.homepage_default_value)));
1191 // Update the font size summary text.
1192 fontSizePreference.setSummary(sharedPreferences.getString("font_size", context.getString(R.string.font_size_default_value)) + "%");
1195 case "open_intents_in_new_tab":
1197 if (sharedPreferences.getBoolean("open_intents_in_new_tab", true)) {
1198 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled);
1200 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled);
1204 case "swipe_to_refresh":
1206 if (sharedPreferences.getBoolean("swipe_to_refresh", true)) {
1207 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
1209 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
1213 case "download_with_external_app":
1215 if (sharedPreferences.getBoolean(context.getString(R.string.download_with_external_app_key), false)) {
1216 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled);
1218 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled);
1222 case "scroll_app_bar":
1224 if (sharedPreferences.getBoolean(context.getString(R.string.scroll_app_bar_key), true)) scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1225 else scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1229 case "bottom_app_bar":
1231 if (sharedPreferences.getBoolean(context.getString(R.string.bottom_app_bar_key), false)) bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled);
1232 else bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled);
1234 // Restart Privacy Browser.
1235 restartPrivacyBrowser();
1238 case "display_additional_app_bar_icons":
1240 if (sharedPreferences.getBoolean(context.getString(R.string.display_additional_app_bar_icons_key), false)) {
1241 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
1243 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
1248 // Get the new theme.
1249 String newAppTheme = sharedPreferences.getString("app_theme", context.getString(R.string.app_theme_default_value));
1251 // 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.
1252 if (newAppTheme.equals(appThemeEntryValuesStringArray[1])) { // The light theme is selected.
1253 // Update the theme preference summary text.
1254 appThemePreference.setSummary(appThemeEntriesStringArray[1]);
1256 // Apply the new theme.
1257 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
1258 } else if (newAppTheme.equals(appThemeEntryValuesStringArray[2])) { // The dark theme is selected.
1259 // Update the theme preference summary text.
1260 appThemePreference.setSummary(appThemeEntriesStringArray[2]);
1262 // Apply the new theme.
1263 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
1264 } else { // The system default theme is selected.
1265 // Update the theme preference summary text.
1266 appThemePreference.setSummary(appThemeEntriesStringArray[0]);
1268 // Apply the new theme.
1269 if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported.
1270 // Follow the system default theme.
1271 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
1272 } else {// The system default theme is not supported.
1273 // Follow the battery saver mode.
1274 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
1278 // Update the current theme status.
1279 currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
1282 case "webview_theme":
1283 // Get the new WebView theme.
1284 String newWebViewTheme = sharedPreferences.getString("webview_theme", context.getString(R.string.webview_theme_default_value));
1286 // Define a new WebView theme entry number.
1287 int newWebViewThemeEntryNumber;
1289 // Get the webView theme entry number that matches the new WebView theme. A switch statement cannot be used because the theme entry values string array is not a compile time constant.
1290 if (newWebViewTheme.equals(webViewThemeEntriesStringArray[1])) { // The light theme is selected.
1291 // Store the new WebView theme entry number.
1292 newWebViewThemeEntryNumber = 1;
1293 } else if (newWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected.
1294 // Store the WebView theme entry number.
1295 newWebViewThemeEntryNumber = 2;
1296 } else { // The system default theme is selected.
1297 // Store the WebView theme entry number.
1298 newWebViewThemeEntryNumber = 0;
1302 switch (newWebViewThemeEntryNumber) {
1303 case 0: // The system default WebView theme is selected.
1305 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1306 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1308 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1312 case 1: // The light theme is selected.
1314 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1317 case 2: // The dark theme is selected.
1319 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1323 // Set the current theme as the summary text for the preference.
1324 webViewThemePreference.setSummary(webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]);
1327 case "wide_viewport":
1329 if (sharedPreferences.getBoolean("wide_viewport", true)) {
1330 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled);
1332 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled);
1336 case "display_webpage_images":
1338 if (sharedPreferences.getBoolean("display_webpage_images", true)) {
1339 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
1341 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
1348 private void restartPrivacyBrowser() {
1349 // Create an intent to restart Privacy Browser.
1350 Intent restartIntent = requireActivity().getParentActivityIntent();
1352 // Assert that the intent is not null to remove the lint error below.
1353 assert restartIntent != null;
1355 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1356 restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1358 // Create a handler to restart the activity.
1359 Handler restartHandler = new Handler(Looper.getMainLooper());
1361 // Create a runnable to restart the activity.
1362 Runnable restartRunnable = () -> {
1363 // Restart the activity.
1364 startActivity(restartIntent);
1366 // Kill this instance of Privacy Browser. Otherwise, the app exhibits sporadic behavior after the restart.
1370 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1371 restartHandler.postDelayed(restartRunnable, 400);