]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java
Combine drawable files. https://redmine.stoutner.com/issues/794
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / fragments / SettingsFragment.java
1 /*
2  * Copyright © 2016-2022 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 package com.stoutner.privacybrowser.fragments;
21
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;
37
38 import androidx.appcompat.app.AppCompatDelegate;
39 import androidx.preference.Preference;
40 import androidx.preference.PreferenceCategory;
41 import androidx.preference.PreferenceFragmentCompat;
42
43 import com.stoutner.privacybrowser.R;
44 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
45 import com.stoutner.privacybrowser.helpers.ProxyHelper;
46
47 import java.util.Objects;
48
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;
61
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 incognitoModePreference;
70     private Preference allowScreenshotsPreference;
71     private Preference easyListPreference;
72     private Preference easyPrivacyPreference;
73     private Preference fanboyAnnoyanceListPreference;
74     private Preference fanboySocialBlockingListPreference;
75     private Preference ultraListPreference;
76     private Preference ultraPrivacyPreference;
77     private Preference blockAllThirdPartyRequestsPreference;
78     private Preference googleAnalyticsPreference;
79     private Preference facebookClickIdsPreference;
80     private Preference twitterAmpRedirectsPreference;
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;
105
106     @Override
107     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
108         // Load the preferences from the XML file.
109         setPreferencesFromResource(R.xml.preferences, rootKey);
110
111         // Get a handle for the activity.
112         Activity activity = getActivity();
113
114         // Remove the lint warning below that `getApplicationContext()` might produce a null pointer exception.
115         assert activity != null;
116
117         // Get a handle for the resources.
118         Resources resources = getResources();
119
120         // Get the current theme status.
121         currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
122
123         // Get a handle for the shared preferences.
124         SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
125
126         // Remove the incorrect warning below that the shared preferences might be null.
127         assert sharedPreferences != null;
128
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         incognitoModePreference = findPreference("incognito_mode");
137         allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key));
138         easyListPreference = findPreference("easylist");
139         easyPrivacyPreference = findPreference("easyprivacy");
140         fanboyAnnoyanceListPreference = findPreference("fanboys_annoyance_list");
141         fanboySocialBlockingListPreference = findPreference("fanboys_social_blocking_list");
142         ultraListPreference = findPreference("ultralist");
143         ultraPrivacyPreference = findPreference("ultraprivacy");
144         blockAllThirdPartyRequestsPreference = findPreference("block_all_third_party_requests");
145         googleAnalyticsPreference = findPreference("google_analytics");
146         facebookClickIdsPreference = findPreference("facebook_click_ids");
147         twitterAmpRedirectsPreference = findPreference("twitter_amp_redirects");
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");
172
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 incognitoModePreference != null;
181         assert allowScreenshotsPreference != null;
182         assert easyListPreference != null;
183         assert easyPrivacyPreference != null;
184         assert fanboyAnnoyanceListPreference != null;
185         assert fanboySocialBlockingListPreference != null;
186         assert ultraListPreference != null;
187         assert ultraPrivacyPreference != null;
188         assert blockAllThirdPartyRequestsPreference != null;
189         assert googleAnalyticsPreference != null;
190         assert facebookClickIdsPreference != null;
191         assert twitterAmpRedirectsPreference != 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;
216
217         // Set the preference dependencies.
218         hideAppBarPreference.setDependency("full_screen_browsing_mode");
219         domStoragePreference.setDependency("javascript");
220
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));
225
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);
232
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");
238
239             // Remove the incorrect lint warnings below that the preference categories might be null.
240             assert privacyCategory != null;
241             assert clearAndExitCategory != null;
242
243             // Remove the form data preferences.
244             privacyCategory.removePreference(formDataPreference);
245             clearAndExitCategory.removePreference(clearFormDataPreference);
246         }
247
248         // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
249         fanboySocialBlockingListPreference.setEnabled(!fanboyAnnoyanceListEnabled);
250
251
252         // Inflate a WebView to get the default user agent.
253         LayoutInflater inflater = getActivity().getLayoutInflater();
254
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);
257
258         // Get a handle for a bare WebView.
259         WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
260
261         // Get the default user agent.
262         defaultUserAgent = bareWebView.getSettings().getUserAgentString();
263
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);
268
269         // Get the array position of the user agent name.
270         int userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName);
271
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);
277                 break;
278
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);
282                 break;
283
284             case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
285                 // Set the summary text.
286                 userAgentPreference.setSummary(R.string.custom_user_agent);
287                 break;
288
289             default:
290                 // Get the user agent summary from the user agent data array.
291                 userAgentPreference.setSummary(translatedUserAgentNamesArray[userAgentArrayPosition] + ":\n" + userAgentDataArray[userAgentArrayPosition]);
292         }
293
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)));
296
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)));
299
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);
304         } else {
305             // Set the array value as the summary text.
306             searchPreference.setSummary(searchString);
307         }
308
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)));
311
312         // Only enable the search custom URL preference if the search is set to `Custom URL`.
313         searchCustomURLPreference.setEnabled(searchString.equals("Custom URL"));
314
315
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));
320                 break;
321
322             case ProxyHelper.TOR:
323                 proxyPreference.setSummary(getString(R.string.tor_enabled));
324                 break;
325
326             case ProxyHelper.I2P:
327                 proxyPreference.setSummary(getString(R.string.i2p_enabled));
328                 break;
329
330             case ProxyHelper.CUSTOM:
331                 proxyPreference.setSummary(getString(R.string.custom_proxy));
332                 break;
333         }
334
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)));
337
338         // Only enable the custom proxy URL if a custom proxy is selected.
339         proxyCustomUrlPreference.setEnabled(proxyString.equals(ProxyHelper.CUSTOM));
340
341
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);
348
349
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)));
352
353
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)) + "%");
356
357
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);
361
362         // Get the current app theme.
363         String currentAppTheme = sharedPreferences.getString("app_theme", getString(R.string.app_theme_default_value));
364
365         // Define an app theme entry number.
366         int appThemeEntryNumber;
367
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;
378         }
379
380         // Set the current theme as the summary text for the preference.
381         appThemePreference.setSummary(appThemeEntriesStringArray[appThemeEntryNumber]);
382
383
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);
387
388         // Get the current WebView theme.
389         String currentWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value));
390
391         // Define a WebView theme entry number.
392         int webViewThemeEntryNumber;
393
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;
404         }
405
406         // Set the current theme as the summary text for the preference.
407         webViewThemePreference.setSummary(webViewThemeEntriesStringArray[webViewThemeEntryNumber]);
408
409
410         // Set the JavaScript icon.
411         if (javaScriptEnabled) {
412             javaScriptPreference.setIcon(R.drawable.javascript_enabled);
413         } else {
414             javaScriptPreference.setIcon(R.drawable.privacy_mode);
415         }
416
417         // Set the cookies icon.
418         if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false)) {
419             cookiesPreference.setIcon(R.drawable.cookies_enabled);
420         } else {
421             cookiesPreference.setIcon(R.drawable.cookies_disabled);
422         }
423
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);
430             }
431         } else {  // The preference is disabled.  The icon should be ghosted.
432             domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
433         }
434
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);
439             } else {
440                 formDataPreference.setIcon(R.drawable.form_data_disabled);
441             }
442         }
443
444         // Set the custom user agent icon.
445         if (customUserAgentPreference.isEnabled()) {
446             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
447         } else {
448             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
449         }
450
451         // Set the incognito mode icon.
452         if (sharedPreferences.getBoolean("incognito_mode", false)) {
453             incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
454         } else {
455             incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
456         }
457
458         // Set the allow screenshots icon.
459         if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)) {
460             allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled);
461         } else {
462             allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled);
463         }
464
465         // Set the EasyList icon.
466         if (sharedPreferences.getBoolean("easylist", true)) {
467             easyListPreference.setIcon(R.drawable.block_ads_enabled);
468         } else {
469             easyListPreference.setIcon(R.drawable.block_ads_disabled);
470         }
471
472         // Set the EasyPrivacy icon.
473         if (sharedPreferences.getBoolean("easyprivacy", true)) {
474             easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
475         } else {
476             easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
477         }
478
479         // Set the Fanboy lists icons.
480         if (fanboyAnnoyanceListEnabled) {
481             // Set the Fanboy annoyance list icon.
482             fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled);
483
484             // Set the Fanboy social blocking list icon.
485             fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted);
486         } else {
487             // Set the Fanboy annoyance list icon.
488             fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled);
489
490             // Set the Fanboy social blocking list icon.
491             if (fanboySocialBlockingEnabled) {
492                 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled);
493             } else {
494                 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled);
495             }
496         }
497
498         // Set the UltraList icon.
499         if (sharedPreferences.getBoolean("ultralist", true)){
500             ultraListPreference.setIcon(R.drawable.block_ads_enabled);
501         } else {
502             ultraListPreference.setIcon(R.drawable.block_ads_disabled);
503         }
504
505         // Set the UltraPrivacy icon.
506         if (sharedPreferences.getBoolean("ultraprivacy", true)) {
507             ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
508         } else {
509             ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
510         }
511
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);
515         } else {
516             blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled);
517         }
518
519         // Set the Google Analytics icon.
520         if (sharedPreferences.getBoolean("google_analytics", true)) {
521             googleAnalyticsPreference.setIcon(R.drawable.modify_url_enabled);
522         } else {
523             googleAnalyticsPreference.setIcon(R.drawable.modify_url_disabled);
524         }
525
526         // Set the Facebook Click IDs icon.
527         if (sharedPreferences.getBoolean("facebook_click_ids", true)) {
528             facebookClickIdsPreference.setIcon(R.drawable.modify_url_enabled);
529         } else {
530             facebookClickIdsPreference.setIcon(R.drawable.modify_url_disabled);
531         }
532
533         // Set the Twitter AMP redirects icon.
534         if (sharedPreferences.getBoolean("twitter_amp_redirects", true)) {
535             twitterAmpRedirectsPreference.setIcon(R.drawable.modify_url_enabled);
536         } else {
537             twitterAmpRedirectsPreference.setIcon(R.drawable.modify_url_disabled);
538         }
539
540         // Set the search custom URL icon.
541         if (searchCustomURLPreference.isEnabled()) {
542             searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled);
543         } else {
544             searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted);
545         }
546
547         // Set the Proxy icons according to the theme and status.
548         if (proxyString.equals(ProxyHelper.NONE)) {  // Proxying is disabled.
549             // Set the main proxy icon to be disabled.
550             proxyPreference.setIcon(R.drawable.proxy_disabled);
551
552             // Set the custom proxy URL icon to be ghosted.
553             proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
554         } else {  // Proxying is enabled.
555             // Set the main proxy icon to be enabled.
556             proxyPreference.setIcon(R.drawable.proxy_enabled);
557
558             // Set the custom proxy URL icon according to its status.
559             if (proxyCustomUrlPreference.isEnabled()) {
560                 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled);
561             } else {
562                 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
563             }
564         }
565
566         // Set the full screen browsing mode icons.
567         if (fullScreenBrowsingMode) {  // Full screen browsing mode is enabled.
568             // Set the full screen browsing mode preference icon.
569             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
570
571             // Set the hide app bar icon.
572             if (sharedPreferences.getBoolean("hide_app_bar", true)) {
573                 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
574             } else {
575                 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
576             }
577         } else {  // Full screen browsing mode is disabled.
578             // Set the icons.
579             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
580             hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted);
581         }
582
583         // Set the clear everything preference icon.
584         if (clearEverything) {
585             clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
586         } else {
587             clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
588         }
589
590         // Set the clear cookies preference icon.
591         if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) {
592             clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
593         } else {
594             clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
595         }
596
597         // Set the clear DOM storage preference icon.
598         if (clearEverything || sharedPreferences.getBoolean("clear_dom_storage", true)) {
599             clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
600         } else {
601             clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
602         }
603
604         // Set the clear form data preference icon if the API < 26.  It has no effect on newer versions of Android.
605         if (Build.VERSION.SDK_INT < 26) {
606             if (clearEverything || sharedPreferences.getBoolean("clear_form_data", true)) {
607                 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
608             } else {
609                 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
610             }
611         }
612
613         // Set the clear logcat preference icon.
614         if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true)) {
615             clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
616         } else {
617             clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled);
618         }
619
620         // Set the clear cache preference icon.
621         if (clearEverything || sharedPreferences.getBoolean("clear_cache", true)) {
622             clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
623         } else {
624             clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
625         }
626
627         // Set the open intents in new tab preference icon.
628         if (sharedPreferences.getBoolean("open_intents_in_new_tab", true)) {
629             openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled);
630         } else {
631             openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled);
632         }
633
634         // Set the swipe to refresh preference icon.
635         if (sharedPreferences.getBoolean("swipe_to_refresh", true)) {
636             swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
637         } else {
638             swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
639         }
640
641         // Set the download with external app preference icon.
642         if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false)) {
643             downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled);
644         } else {
645             downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled);
646         }
647
648         // Set the scroll app bar preference icon.
649         if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true)) {
650             scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled);
651         } else {
652             scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled);
653         }
654
655         // Set the bottom app bar preference icon.
656         if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
657             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled);
658         } else {
659             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled);
660         }
661
662         // Set the display additional app bar icons preference icon.
663         if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false)) {
664             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
665         } else {
666             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
667         }
668
669         // Set the WebView theme preference icon.
670         switch (webViewThemeEntryNumber) {
671             case 0:  // The system default WebView theme is selected.
672                 // Set the icon according to the app theme.
673                 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
674                     webViewThemePreference.setIcon(R.drawable.webview_light_theme);
675                 } else {
676                     webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
677                 }
678                 break;
679
680             case 1:  // The light WebView theme is selected.
681                 // Set the icon.
682                 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
683                 break;
684
685             case 2:  // The dark WebView theme is selected.
686                 // Set the icon.
687                 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
688                 break;
689         }
690
691         // Set the wide viewport preference icon.
692         if (sharedPreferences.getBoolean("wide_viewport", true)) {
693             wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled);
694         } else {
695             wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled);
696         }
697
698         // Set the display webpage images preference icon.
699         if (sharedPreferences.getBoolean("display_webpage_images", true)) {
700             displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
701         } else {
702             displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
703         }
704     }
705
706     // The listener should be unregistered when the app is paused.
707     @Override
708     public void onPause() {
709         // Run the default commands.
710         super.onPause();
711
712         // Get a handle for the shared preferences.
713         SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
714
715         // Remove the incorrect lint warning below that the shared preferences might be null.
716         assert sharedPreferences != null;
717
718         // Unregister the shared preference listener.
719         sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
720     }
721
722     // The listener should be re-registered when the app is resumed.
723     @Override
724     public void onResume() {
725         // Run the default commands.
726         super.onResume();
727
728         // Get a new shared preference change listener.
729         sharedPreferenceChangeListener = getSharedPreferenceChangeListener(requireContext());
730
731         // Get a handle for the shared preferences.
732         SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
733
734         // Remove the incorrect lint warning below that the shared preferences might be null.
735         assert sharedPreferences != null;
736
737         // Re-register the shared preference listener.
738         sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
739     }
740
741     // 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.
742     // This can be removed at some future point, perhaps after the switch to PreferenceScreenCompat.  It isn't an issue in Privacy Cell.
743     private SharedPreferences.OnSharedPreferenceChangeListener getSharedPreferenceChangeListener(Context context) {
744         // Return the shared preference change listener.
745         return (SharedPreferences sharedPreferences, String key) -> {
746             switch (key) {
747                 case "javascript":
748                     // Update the icons and the DOM storage preference status.
749                     if (sharedPreferences.getBoolean("javascript", false)) {  // The JavaScript preference is enabled.
750                         // Update the icon for the JavaScript preference.
751                         javaScriptPreference.setIcon(R.drawable.javascript_enabled);
752
753                         // Update the status of the DOM storage preference.
754                         domStoragePreference.setEnabled(true);
755
756                         // Update the icon for the DOM storage preference.
757                         if (sharedPreferences.getBoolean("dom_storage", false)) {
758                             domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
759                         } else {
760                             domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
761                         }
762                     } else {  // The JavaScript preference is disabled.
763                         // Update the icon for the JavaScript preference.
764                         javaScriptPreference.setIcon(R.drawable.privacy_mode);
765
766                         // Update the status of the DOM storage preference.
767                         domStoragePreference.setEnabled(false);
768
769                         // Set the icon for DOM storage preference to be ghosted.
770                         domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
771                     }
772                     break;
773
774                 case "cookies":
775                     // Update the icon.
776                     if (sharedPreferences.getBoolean(context.getString(R.string.cookies_key), false)) {
777                         cookiesPreference.setIcon(R.drawable.cookies_enabled);
778                     } else {
779                         cookiesPreference.setIcon(R.drawable.cookies_disabled);
780                     }
781                     break;
782
783                 case "dom_storage":
784                     // Update the icon.
785                     if (sharedPreferences.getBoolean("dom_storage", false)) {
786                         domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
787                     } else {
788                         domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
789                     }
790                     break;
791
792                 // Save form data can be removed once the minimum API >= 26.
793                 case "save_form_data":
794                     // Update the icon.
795                     if (sharedPreferences.getBoolean("save_form_data", false)) {
796                         formDataPreference.setIcon(R.drawable.form_data_enabled);
797                     } else {
798                         formDataPreference.setIcon(R.drawable.form_data_disabled);
799                     }
800                     break;
801
802                 case "user_agent":
803                     // Get the new user agent name.
804                     String newUserAgentName = sharedPreferences.getString("user_agent", context.getString(R.string.user_agent_default_value));
805
806                     // Get the array position for the new user agent name.
807                     int newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName);
808
809                     // Get the translated new user agent name.
810                     String translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition];
811
812                     // Populate the user agent summary.
813                     switch (newUserAgentArrayPosition) {
814                         case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
815                             // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
816                             userAgentPreference.setSummary(translatedNewUserAgentName + ":\n" + defaultUserAgent);
817
818                             // Disable the custom user agent preference.
819                             customUserAgentPreference.setEnabled(false);
820
821                             // Set the custom user agent preference icon.
822                             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
823                             break;
824
825                         case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
826                             // Set the summary text.
827                             userAgentPreference.setSummary(R.string.custom_user_agent);
828
829                             // Enable the custom user agent preference.
830                             customUserAgentPreference.setEnabled(true);
831
832                             // Set the custom user agent preference icon.
833                             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
834                             break;
835
836                         default:
837                             // Get the user agent summary from the user agent data array.
838                             userAgentPreference.setSummary(translatedNewUserAgentName + ":\n" + userAgentDataArray[newUserAgentArrayPosition]);
839
840                             // Disable the custom user agent preference.
841                             customUserAgentPreference.setEnabled(false);
842
843                             // Set the custom user agent preference icon.
844                             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
845                     }
846                     break;
847
848                 case "custom_user_agent":
849                     // Set the new custom user agent as the summary text for the preference.
850                     customUserAgentPreference.setSummary(sharedPreferences.getString("custom_user_agent", context.getString(R.string.custom_user_agent_default_value)));
851                     break;
852
853                 case "incognito_mode":
854                     // Update the icon.
855                     if (sharedPreferences.getBoolean("incognito_mode", false)) {
856                         incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
857                     } else {
858                         incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
859                     }
860                     break;
861
862                 case "allow_screenshots":
863                     // Update the icon.
864                     if (sharedPreferences.getBoolean(context.getString(R.string.allow_screenshots_key), false)) {
865                         allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled);
866                     } else {
867                         allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled);
868                     }
869
870                     // Restart Privacy Browser.
871                     restartPrivacyBrowser();
872                     break;
873
874                 case "easylist":
875                     // Update the icon.
876                     if (sharedPreferences.getBoolean("easylist", true)) {
877                         easyListPreference.setIcon(R.drawable.block_ads_enabled);
878                     } else {
879                         easyListPreference.setIcon(R.drawable.block_ads_disabled);
880                     }
881                     break;
882
883                 case "easyprivacy":
884                     // Update the icon.
885                     if (sharedPreferences.getBoolean("easyprivacy", true)) {
886                         easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
887                     } else {
888                         easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
889                     }
890                     break;
891
892                 case "fanboys_annoyance_list":
893                     boolean currentFanboyAnnoyanceList = sharedPreferences.getBoolean("fanboys_annoyance_list", true);
894                     boolean currentFanboySocialBlockingList = sharedPreferences.getBoolean("fanboys_social_blocking_list", true);
895
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);
900
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);
906
907                         // Update the Fanboy's social blocking list icon.
908                         if (currentFanboySocialBlockingList) {
909                             fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled);
910                         } else {
911                             fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled);
912                         }
913                     }
914
915                     // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
916                     fanboySocialBlockingListPreference.setEnabled(!currentFanboyAnnoyanceList);
917                     break;
918
919                 case "fanboys_social_blocking_list":
920                     // Update the icon.
921                     if (sharedPreferences.getBoolean("fanboys_social_blocking_list", true)) {
922                         fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled);
923                     } else {
924                         fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled);
925                     }
926                     break;
927
928                 case "ultralist":
929                     // Update the icon.
930                     if (sharedPreferences.getBoolean("ultralist", true)) {
931                         ultraListPreference.setIcon(R.drawable.block_ads_enabled);
932                     } else {
933                         ultraListPreference.setIcon(R.drawable.block_ads_disabled);
934                     }
935                     break;
936
937                 case "ultraprivacy":
938                     // Update the icon.
939                     if (sharedPreferences.getBoolean("ultraprivacy", true)) {
940                         ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
941                     } else {
942                         ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
943                     }
944                     break;
945
946                 case "block_all_third_party_requests":
947                     // Update the icon.
948                     if (sharedPreferences.getBoolean("block_all_third_party_requests", false)) {
949                         blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled);
950                     } else {
951                         blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled);
952                     }
953                     break;
954
955                 case "google_analytics":
956                     // Update the icon.
957                     if (sharedPreferences.getBoolean("google_analytics", true)) {
958                         googleAnalyticsPreference.setIcon(R.drawable.modify_url_enabled);
959                     } else {
960                         googleAnalyticsPreference.setIcon(R.drawable.modify_url_disabled);
961                     }
962                     break;
963
964                 case "facebook_click_ids":
965                     // Update the icon.
966                     if (sharedPreferences.getBoolean("facebook_click_ids", true)) {
967                         facebookClickIdsPreference.setIcon(R.drawable.modify_url_enabled);
968                     } else {
969                         facebookClickIdsPreference.setIcon(R.drawable.modify_url_disabled);
970                     }
971                     break;
972
973                 case "twitter_amp_redirects":
974                     // Update the icon.
975                     if (sharedPreferences.getBoolean("twitter_amp_redirects", true)) {
976                         twitterAmpRedirectsPreference.setIcon(R.drawable.modify_url_enabled);
977                     } else {
978                         twitterAmpRedirectsPreference.setIcon(R.drawable.modify_url_disabled);
979                     }
980                     break;
981
982                 case "search":
983                     // Store the new search string.
984                     String newSearchString = sharedPreferences.getString("search", context.getString(R.string.search_default_value));
985
986                     // Update the search and search custom URL preferences.
987                     if (newSearchString.equals("Custom URL")) {  // `Custom URL` is selected.
988                         // Set the summary text to `R.string.custom_url`, which is translated.
989                         searchPreference.setSummary(R.string.custom_url);
990
991                         // Enable the search custom URL preference.
992                         searchCustomURLPreference.setEnabled(true);
993
994                         // Set the search custom URL preference icon.
995                         searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled);
996                     } else {  // `Custom URL` is not selected.
997                         // Set the summary text to `newSearchString`.
998                         searchPreference.setSummary(newSearchString);
999
1000                         // Disable `searchCustomURLPreference`.
1001                         searchCustomURLPreference.setEnabled(false);
1002
1003                         // Set the search custom URL preference icon.
1004                         searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted);
1005                     }
1006                     break;
1007
1008                 case "search_custom_url":
1009                     // Set the new search custom URL as the summary text for the preference.
1010                     searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", context.getString(R.string.search_custom_url_default_value)));
1011                     break;
1012
1013                 case "proxy":
1014                     // Get current proxy string.
1015                     String currentProxyString = sharedPreferences.getString("proxy", context.getString(R.string.proxy_default_value));
1016
1017                     // Update the summary text for the proxy preference.
1018                     switch (currentProxyString) {
1019                         case ProxyHelper.NONE:
1020                             proxyPreference.setSummary(context.getString(R.string.no_proxy_enabled));
1021                             break;
1022
1023                         case ProxyHelper.TOR:
1024                             proxyPreference.setSummary(context.getString(R.string.tor_enabled));
1025                             break;
1026
1027                         case ProxyHelper.I2P:
1028                             proxyPreference.setSummary(context.getString(R.string.i2p_enabled));
1029                             break;
1030
1031                         case ProxyHelper.CUSTOM:
1032                             proxyPreference.setSummary(context.getString(R.string.custom_proxy));
1033                             break;
1034                     }
1035
1036                     // Update the status of the custom URL preference.
1037                     proxyCustomUrlPreference.setEnabled(currentProxyString.equals(ProxyHelper.CUSTOM));
1038
1039                     // Update the icons.
1040                     if (currentProxyString.equals(ProxyHelper.NONE)) {  // Proxying is disabled.
1041                         // Set the main proxy icon to be disabled
1042                         proxyPreference.setIcon(R.drawable.proxy_disabled);
1043
1044                         // Set the custom proxy URL icon to be ghosted.
1045                         proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
1046                     } else {  // Proxying is enabled.
1047                         // Set the main proxy icon to be enabled.
1048                         proxyPreference.setIcon(R.drawable.proxy_enabled);
1049
1050                         /// Set the custom proxy URL icon according to its status.
1051                         if (proxyCustomUrlPreference.isEnabled()) {
1052                             proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled);
1053                         } else {
1054                             proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
1055                         }
1056                     }
1057                     break;
1058
1059                 case "proxy_custom_url":
1060                     // Set the summary text for the proxy custom URL.
1061                     proxyCustomUrlPreference.setSummary(sharedPreferences.getString(context.getString(R.string.proxy_custom_url_key), context.getString(R.string.proxy_custom_url_default_value)));
1062                     break;
1063
1064                 case "full_screen_browsing_mode":
1065                     if (sharedPreferences.getBoolean("full_screen_browsing_mode", false)) {  // Full screen browsing is enabled.
1066                         // Set the full screen browsing mode preference icon.
1067                         fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
1068
1069                         // Set the hide app bar preference icon.
1070                         if (sharedPreferences.getBoolean("hide_app_bar", true)) {
1071                             hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1072                         } else {
1073                             hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1074                         }
1075                     } else {  // Full screen browsing is disabled.
1076                         // Update the icons.
1077                         fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
1078                         hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted);
1079                     }
1080                     break;
1081
1082                 case "hide_app_bar":
1083                     // Update the icon.
1084                     if (sharedPreferences.getBoolean("hide_app_bar", true)) {
1085                         hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1086                     } else {  // Hide app bar is disabled.
1087                         // Set the icon according to the theme.
1088                         hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1089                     }
1090                     break;
1091
1092                 case "clear_everything":
1093                     // Store the new clear everything status
1094                     boolean newClearEverythingBoolean = sharedPreferences.getBoolean("clear_everything", true);
1095
1096                     // Update the status of the clear and exit preferences.
1097                     clearCookiesPreference.setEnabled(!newClearEverythingBoolean);
1098                     clearDomStoragePreference.setEnabled(!newClearEverythingBoolean);
1099                     clearFormDataPreference.setEnabled(!newClearEverythingBoolean);  // This line can be removed once the minimum API >= 26.
1100                     clearLogcatPreference.setEnabled(!newClearEverythingBoolean);
1101                     clearCachePreference.setEnabled(!newClearEverythingBoolean);
1102
1103                     // Update the clear everything preference icon.
1104                     if (newClearEverythingBoolean) {
1105                         clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
1106                     } else {
1107                         clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
1108                     }
1109
1110                     // Update the clear cookies preference icon.
1111                     if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cookies", true)) {
1112                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
1113                     } else {
1114                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
1115                     }
1116
1117                     // Update the clear dom storage preference icon.
1118                     if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_dom_storage", true)) {
1119                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
1120                     } else {
1121                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
1122                     }
1123
1124                     // Update the clear form data preference icon if the API < 26.
1125                     if (Build.VERSION.SDK_INT < 26) {
1126                         if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_form_data", true)) {
1127                             clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
1128                         } else {
1129                             clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
1130                         }
1131                     }
1132
1133                     // Update the clear logcat preference icon.
1134                     if (newClearEverythingBoolean || sharedPreferences.getBoolean(context.getString(R.string.clear_logcat_key), true)) {
1135                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
1136                     } else {
1137                         clearLogcatPreference.setIcon(R.drawable.clear_cache_disabled);
1138                     }
1139
1140                     // Update the clear cache preference icon.
1141                     if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cache", true)) {
1142                         clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
1143                     } else {
1144                         clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
1145                     }
1146                     break;
1147
1148                 case "clear_cookies":
1149                     // Update the icon.
1150                     if (sharedPreferences.getBoolean("clear_cookies", true)) {
1151                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
1152                     } else {
1153                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
1154                     }
1155                     break;
1156
1157                 case "clear_dom_storage":
1158                     // Update the icon.
1159                     if (sharedPreferences.getBoolean("clear_dom_storage", true)) {
1160                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
1161                     } else {
1162                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
1163                     }
1164                     break;
1165
1166                 // This section can be removed once the minimum API >= 26.
1167                 case "clear_form_data":
1168                     // Update the icon.
1169                     if (sharedPreferences.getBoolean("clear_form_data", true)) {
1170                         clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
1171                     } else {
1172                         clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
1173                     }
1174                     break;
1175
1176                 case "clear_logcat":
1177                     // Update the icon.
1178                     if (sharedPreferences.getBoolean(context.getString(R.string.clear_logcat_key), true)) {
1179                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
1180                     } else {
1181                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled);
1182                     }
1183                     break;
1184
1185                 case "clear_cache":
1186                     // Update the icon.
1187                     if (sharedPreferences.getBoolean("clear_cache", true)) {
1188                         clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
1189                     } else {
1190                         clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
1191                     }
1192                     break;
1193
1194                 case "homepage":
1195                     // Set the new homepage URL as the summary text for the Homepage preference.
1196                     homepagePreference.setSummary(sharedPreferences.getString("homepage", context.getString(R.string.homepage_default_value)));
1197                     break;
1198
1199                 case "font_size":
1200                     // Update the font size summary text.
1201                     fontSizePreference.setSummary(sharedPreferences.getString("font_size", context.getString(R.string.font_size_default_value)) + "%");
1202                     break;
1203
1204                 case "open_intents_in_new_tab":
1205                     // Update the icon.
1206                     if (sharedPreferences.getBoolean("open_intents_in_new_tab", true)) {
1207                         openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled);
1208                     } else {
1209                         openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled);
1210                     }
1211                     break;
1212
1213                 case "swipe_to_refresh":
1214                     // Update the icon.
1215                     if (sharedPreferences.getBoolean("swipe_to_refresh", true)) {
1216                         swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
1217                     } else {
1218                         swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
1219                     }
1220                     break;
1221
1222                 case "download_with_external_app":
1223                     // Update the icon.
1224                     if (sharedPreferences.getBoolean(context.getString(R.string.download_with_external_app_key), false)) {
1225                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled);
1226                     } else {
1227                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled);
1228                     }
1229                     break;
1230
1231                 case "scroll_app_bar":
1232                     // Update the icon.
1233                     if (sharedPreferences.getBoolean(context.getString(R.string.scroll_app_bar_key), true)) {
1234                         scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1235                     } else {
1236                         scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1237                     }
1238                     break;
1239
1240                 case "bottom_app_bar":
1241                     // Update the icon.
1242                     if (sharedPreferences.getBoolean(context.getString(R.string.bottom_app_bar_key), false)) {
1243                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled);
1244                     } else {
1245                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled);
1246                     }
1247
1248                     // Restart Privacy Browser.
1249                     restartPrivacyBrowser();
1250                     break;
1251
1252                 case "display_additional_app_bar_icons":
1253                     // Update the icon.
1254                     if (sharedPreferences.getBoolean(context.getString(R.string.display_additional_app_bar_icons_key), false)) {
1255                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
1256                     } else {
1257                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
1258                     }
1259                     break;
1260
1261                 case "app_theme":
1262                     // Get the new theme.
1263                     String newAppTheme = sharedPreferences.getString("app_theme", context.getString(R.string.app_theme_default_value));
1264
1265                     // 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.
1266                     if (newAppTheme.equals(appThemeEntryValuesStringArray[1])) {  // The light theme is selected.
1267                         // Update the theme preference summary text.
1268                         appThemePreference.setSummary(appThemeEntriesStringArray[1]);
1269
1270                         // Apply the new theme.
1271                         AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
1272                     } else if (newAppTheme.equals(appThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
1273                         // Update the theme preference summary text.
1274                         appThemePreference.setSummary(appThemeEntriesStringArray[2]);
1275
1276                         // Apply the new theme.
1277                         AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
1278                     } else {  // The system default theme is selected.
1279                         // Update the theme preference summary text.
1280                         appThemePreference.setSummary(appThemeEntriesStringArray[0]);
1281
1282                         // Apply the new theme.
1283                         if (Build.VERSION.SDK_INT >= 28) {  // The system default theme is supported.
1284                             // Follow the system default theme.
1285                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
1286                         } else {// The system default theme is not supported.
1287                             // Follow the battery saver mode.
1288                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
1289                         }
1290                     }
1291
1292                     // Update the current theme status.
1293                     currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
1294                     break;
1295
1296                 case "webview_theme":
1297                     // Get the new WebView theme.
1298                     String newWebViewTheme = sharedPreferences.getString("webview_theme", context.getString(R.string.webview_theme_default_value));
1299
1300                     // Define a new WebView theme entry number.
1301                     int newWebViewThemeEntryNumber;
1302
1303                     // 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.
1304                     if (newWebViewTheme.equals(webViewThemeEntriesStringArray[1])) {  // The light theme is selected.
1305                         // Store the new WebView theme entry number.
1306                         newWebViewThemeEntryNumber = 1;
1307                     } else if (newWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
1308                         // Store the WebView theme entry number.
1309                         newWebViewThemeEntryNumber = 2;
1310                     } else {  // The system default theme is selected.
1311                         // Store the WebView theme entry number.
1312                         newWebViewThemeEntryNumber = 0;
1313                     }
1314
1315                     // Update the icon.
1316                     switch (newWebViewThemeEntryNumber) {
1317                         case 0:  // The system default WebView theme is selected.
1318                             // Set the icon.
1319                             if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1320                                 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1321                             } else {
1322                                 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1323                             }
1324                             break;
1325
1326                         case 1:  // The light theme is selected.
1327                             // Set the icon.
1328                             webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1329                             break;
1330
1331                         case 2:  // The dark theme is selected.
1332                             // Set the icon.
1333                             webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1334                             break;
1335                     }
1336
1337                     // Set the current theme as the summary text for the preference.
1338                     webViewThemePreference.setSummary(webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]);
1339                     break;
1340
1341                 case "wide_viewport":
1342                     // Update the icon.
1343                     if (sharedPreferences.getBoolean("wide_viewport", true)) {
1344                         wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled);
1345                     } else {
1346                         wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled);
1347                     }
1348                     break;
1349
1350                 case "display_webpage_images":
1351                     // Update the icon.
1352                     if (sharedPreferences.getBoolean("display_webpage_images", true)) {
1353                         displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
1354                     } else {
1355                         displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
1356                     }
1357                     break;
1358             }
1359         };
1360     }
1361
1362     private void restartPrivacyBrowser() {
1363         // Create an intent to restart Privacy Browser.
1364         Intent restartIntent = requireActivity().getParentActivityIntent();
1365
1366         // Assert that the intent is not null to remove the lint error below.
1367         assert restartIntent != null;
1368
1369         // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack.  It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1370         restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1371
1372         // Create a handler to restart the activity.
1373         Handler restartHandler = new Handler(Looper.getMainLooper());
1374
1375         // Create a runnable to restart the activity.
1376         Runnable restartRunnable = () -> {
1377             // Restart the activity.
1378             startActivity(restartIntent);
1379
1380             // Kill this instance of Privacy Browser.  Otherwise, the app exhibits sporadic behavior after the restart.
1381             System.exit(0);
1382         };
1383
1384         // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1385         restartHandler.postDelayed(restartRunnable, 400);
1386     }
1387 }