]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java
First wrong button text in View Headers in night theme. https://redmine.stoutner...
[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 String defaultUserAgent;
52     private ArrayAdapter<CharSequence> userAgentNamesArray;
53     private String[] translatedUserAgentNamesArray;
54     private String[] userAgentDataArray;
55     private String[] appThemeEntriesStringArray;
56     private String[] appThemeEntryValuesStringArray;
57     private String[] webViewThemeEntriesStringArray;
58     private String[] webViewThemeEntryValuesStringArray;
59     private SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener;
60
61     // Declare the class views.
62     private Preference javaScriptPreference;
63     private Preference cookiesPreference;
64     private Preference domStoragePreference;
65     private Preference formDataPreference;  // The form data preference can be removed once the minimum API >= 26.
66     private Preference userAgentPreference;
67     private Preference customUserAgentPreference;
68     private Preference xRequestedWithHeaderPreference;
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 trackingQueriesPreference;
79     private Preference ampRedirectsPreference;
80     private Preference searchPreference;
81     private Preference searchCustomURLPreference;
82     private Preference proxyPreference;
83     private Preference proxyCustomUrlPreference;
84     private Preference fullScreenBrowsingModePreference;
85     private Preference hideAppBarPreference;
86     private Preference clearEverythingPreference;
87     private Preference clearCookiesPreference;
88     private Preference clearDomStoragePreference;
89     private Preference clearFormDataPreference;  // The clear form data preference can be removed once the minimum API >= 26.
90     private Preference clearLogcatPreference;
91     private Preference clearCachePreference;
92     private Preference homepagePreference;
93     private Preference fontSizePreference;
94     private Preference openIntentsInNewTabPreference;
95     private Preference swipeToRefreshPreference;
96     private Preference downloadWithExternalAppPreference;
97     private Preference scrollAppBarPreference;
98     private Preference bottomAppBarPreference;
99     private Preference displayAdditionalAppBarIconsPreference;
100     private Preference appThemePreference;
101     private Preference webViewThemePreference;
102     private Preference wideViewportPreference;
103     private Preference displayWebpageImagesPreference;
104
105     @Override
106     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
107         // Load the preferences from the XML file.
108         setPreferencesFromResource(R.xml.preferences, rootKey);
109
110         // Get a handle for the activity.
111         Activity activity = getActivity();
112
113         // Remove the lint warning below that `getApplicationContext()` might produce a null pointer exception.
114         assert activity != null;
115
116         // Get a handle for the resources.
117         Resources resources = getResources();
118
119         // Get a handle for the shared preferences.
120         SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
121
122         // Remove the incorrect warning below that the shared preferences might be null.
123         assert sharedPreferences != null;
124
125         // Get handles for the preferences.
126         javaScriptPreference = findPreference("javascript");
127         cookiesPreference = findPreference(getString(R.string.cookies_key));
128         domStoragePreference = findPreference("dom_storage");
129         formDataPreference = findPreference("save_form_data");  // The form data preference can be removed once the minimum API >= 26.
130         userAgentPreference = findPreference("user_agent");
131         customUserAgentPreference = findPreference("custom_user_agent");
132         xRequestedWithHeaderPreference = findPreference(getString(R.string.x_requested_with_header_key));
133         incognitoModePreference = findPreference("incognito_mode");
134         allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key));
135         easyListPreference = findPreference("easylist");
136         easyPrivacyPreference = findPreference("easyprivacy");
137         fanboyAnnoyanceListPreference = findPreference("fanboys_annoyance_list");
138         fanboySocialBlockingListPreference = findPreference("fanboys_social_blocking_list");
139         ultraListPreference = findPreference("ultralist");
140         ultraPrivacyPreference = findPreference("ultraprivacy");
141         blockAllThirdPartyRequestsPreference = findPreference("block_all_third_party_requests");
142         trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key));
143         ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key));
144         searchPreference = findPreference("search");
145         searchCustomURLPreference = findPreference("search_custom_url");
146         proxyPreference = findPreference("proxy");
147         proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key));
148         fullScreenBrowsingModePreference = findPreference("full_screen_browsing_mode");
149         hideAppBarPreference = findPreference("hide_app_bar");
150         clearEverythingPreference = findPreference("clear_everything");
151         clearCookiesPreference = findPreference("clear_cookies");
152         clearDomStoragePreference = findPreference("clear_dom_storage");
153         clearFormDataPreference = findPreference("clear_form_data");  // The clear form data preference can be removed once the minimum API >= 26.
154         clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key));
155         clearCachePreference = findPreference("clear_cache");
156         homepagePreference = findPreference("homepage");
157         fontSizePreference = findPreference("font_size");
158         openIntentsInNewTabPreference = findPreference("open_intents_in_new_tab");
159         swipeToRefreshPreference = findPreference("swipe_to_refresh");
160         downloadWithExternalAppPreference = findPreference(getString(R.string.download_with_external_app_key));
161         scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key));
162         bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key));
163         displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key));
164         appThemePreference = findPreference("app_theme");
165         webViewThemePreference = findPreference("webview_theme");
166         wideViewportPreference = findPreference("wide_viewport");
167         displayWebpageImagesPreference = findPreference("display_webpage_images");
168
169         // Remove the lint warnings below that the preferences might be null.
170         assert javaScriptPreference != null;
171         assert cookiesPreference != null;
172         assert domStoragePreference != null;
173         assert formDataPreference != null;
174         assert userAgentPreference != null;
175         assert customUserAgentPreference != null;
176         assert xRequestedWithHeaderPreference != null;
177         assert incognitoModePreference != null;
178         assert allowScreenshotsPreference != null;
179         assert easyListPreference != null;
180         assert easyPrivacyPreference != null;
181         assert fanboyAnnoyanceListPreference != null;
182         assert fanboySocialBlockingListPreference != null;
183         assert ultraListPreference != null;
184         assert ultraPrivacyPreference != null;
185         assert blockAllThirdPartyRequestsPreference != null;
186         assert trackingQueriesPreference != null;
187         assert ampRedirectsPreference != null;
188         assert searchPreference != null;
189         assert searchCustomURLPreference != null;
190         assert proxyPreference != null;
191         assert proxyCustomUrlPreference != null;
192         assert fullScreenBrowsingModePreference != null;
193         assert hideAppBarPreference != null;
194         assert clearEverythingPreference != null;
195         assert clearCookiesPreference != null;
196         assert clearDomStoragePreference != null;
197         assert clearFormDataPreference != null;
198         assert clearLogcatPreference != null;
199         assert clearCachePreference != null;
200         assert homepagePreference != null;
201         assert fontSizePreference != null;
202         assert openIntentsInNewTabPreference != null;
203         assert swipeToRefreshPreference != null;
204         assert downloadWithExternalAppPreference != null;
205         assert scrollAppBarPreference != null;
206         assert bottomAppBarPreference != null;
207         assert displayAdditionalAppBarIconsPreference != null;
208         assert appThemePreference != null;
209         assert webViewThemePreference != null;
210         assert wideViewportPreference != null;
211         assert displayWebpageImagesPreference != null;
212
213         // Set the preference dependencies.
214         hideAppBarPreference.setDependency("full_screen_browsing_mode");
215         domStoragePreference.setDependency("javascript");
216
217         // Get strings from the preferences.
218         String userAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
219         String searchString = sharedPreferences.getString("search", getString(R.string.search_default_value));
220         String proxyString = sharedPreferences.getString("proxy", getString(R.string.proxy_default_value));
221
222         // Get booleans that are used in multiple places from the preferences.
223         boolean javaScriptEnabled = sharedPreferences.getBoolean("javascript", false);
224         boolean fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean("fanboys_annoyance_list", true);
225         boolean fanboySocialBlockingEnabled = sharedPreferences.getBoolean("fanboys_social_blocking_list", true);
226         boolean fullScreenBrowsingMode = sharedPreferences.getBoolean("full_screen_browsing_mode", false);
227         boolean clearEverything = sharedPreferences.getBoolean("clear_everything", true);
228
229         // Remove the form data preferences if the API is >= 26 as they no longer do anything.
230         if (Build.VERSION.SDK_INT >= 26) {
231             // Get handles for the categories.
232             PreferenceCategory privacyCategory = findPreference("privacy");
233             PreferenceCategory clearAndExitCategory = findPreference("clear_and_exit");
234
235             // Remove the incorrect lint warnings below that the preference categories might be null.
236             assert privacyCategory != null;
237             assert clearAndExitCategory != null;
238
239             // Remove the form data preferences.
240             privacyCategory.removePreference(formDataPreference);
241             clearAndExitCategory.removePreference(clearFormDataPreference);
242         }
243
244         // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
245         fanboySocialBlockingListPreference.setEnabled(!fanboyAnnoyanceListEnabled);
246
247
248         // Inflate a WebView to get the default user agent.
249         LayoutInflater inflater = getActivity().getLayoutInflater();
250
251         // `@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.
252         @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
253
254         // Get a handle for a bare WebView.
255         WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
256
257         // Get the default user agent.
258         defaultUserAgent = bareWebView.getSettings().getUserAgentString();
259
260         // Get the user agent arrays.
261         userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item);
262         translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names);
263         userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
264
265         // Get the array position of the user agent name.
266         int userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName);
267
268         // Populate the user agent summary.
269         switch (userAgentArrayPosition) {
270             case MainWebViewActivity.UNRECOGNIZED_USER_AGENT:  // The user agent name is not on the canonical list.
271                 // 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.
272                 userAgentPreference.setSummary(userAgentName);
273                 break;
274
275             case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
276                 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
277                 userAgentPreference.setSummary(translatedUserAgentNamesArray[userAgentArrayPosition] + ":\n" + defaultUserAgent);
278                 break;
279
280             case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
281                 // Set the summary text.
282                 userAgentPreference.setSummary(R.string.custom_user_agent);
283                 break;
284
285             default:
286                 // Get the user agent summary from the user agent data array.
287                 userAgentPreference.setSummary(translatedUserAgentNamesArray[userAgentArrayPosition] + ":\n" + userAgentDataArray[userAgentArrayPosition]);
288         }
289
290         // Set the summary text for the custom user agent preference.
291         customUserAgentPreference.setSummary(sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value)));
292
293         // Only enable the custom user agent preference if the user agent is set to `Custom`.
294         customUserAgentPreference.setEnabled(Objects.equals(userAgentPreference.getSummary(), getString(R.string.custom_user_agent)));
295
296         // Set the search URL as the summary text for the search preference when the preference screen is loaded.
297         if (searchString.equals("Custom URL")) {
298             // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
299             searchPreference.setSummary(R.string.custom_url);
300         } else {
301             // Set the array value as the summary text.
302             searchPreference.setSummary(searchString);
303         }
304
305         // Set the summary text for the search custom URL (the default is `""`).
306         searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", getString(R.string.search_custom_url_default_value)));
307
308         // Only enable the search custom URL preference if the search is set to `Custom URL`.
309         searchCustomURLPreference.setEnabled(searchString.equals("Custom URL"));
310
311
312         // Set the summary text for the proxy preference when the preference screen is loaded.
313         switch (proxyString) {
314             case ProxyHelper.NONE:
315                 proxyPreference.setSummary(getString(R.string.no_proxy_enabled));
316                 break;
317
318             case ProxyHelper.TOR:
319                 proxyPreference.setSummary(getString(R.string.tor_enabled));
320                 break;
321
322             case ProxyHelper.I2P:
323                 proxyPreference.setSummary(getString(R.string.i2p_enabled));
324                 break;
325
326             case ProxyHelper.CUSTOM:
327                 proxyPreference.setSummary(getString(R.string.custom_proxy));
328                 break;
329         }
330
331         // Set the summary text for the custom proxy URL.
332         proxyCustomUrlPreference.setSummary(sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value)));
333
334         // Only enable the custom proxy URL if a custom proxy is selected.
335         proxyCustomUrlPreference.setEnabled(proxyString.equals(ProxyHelper.CUSTOM));
336
337
338         // Set the status of the clear and exit preferences.
339         clearCookiesPreference.setEnabled(!clearEverything);
340         clearDomStoragePreference.setEnabled(!clearEverything);
341         clearFormDataPreference.setEnabled(!clearEverything);  // The form data line can be removed once the minimum API is >= 26.
342         clearLogcatPreference.setEnabled(!clearEverything);
343         clearCachePreference.setEnabled(!clearEverything);
344
345
346         // Set the homepage URL as the summary text for the homepage preference.
347         homepagePreference.setSummary(sharedPreferences.getString("homepage", getString(R.string.homepage_default_value)));
348
349
350         // Set the font size as the summary text for the preference.
351         fontSizePreference.setSummary(sharedPreferences.getString("font_size", getString(R.string.font_size_default_value)) + "%");
352
353
354         // Get the app theme string arrays.
355         appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries);
356         appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values);
357
358         // Get the current app theme.
359         String currentAppTheme = sharedPreferences.getString("app_theme", getString(R.string.app_theme_default_value));
360
361         // Declare an app theme entry number.
362         int appThemeEntryNumber;
363
364         // 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.
365         if (currentAppTheme.equals(appThemeEntryValuesStringArray[1])) {  // The light theme is selected.
366             // Store the app theme entry number.
367             appThemeEntryNumber = 1;
368         } else if (currentAppTheme.equals(appThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
369             // Store the app theme entry number.
370             appThemeEntryNumber = 2;
371         } else {  // The system default theme is selected.
372             // Store the app theme entry number.
373             appThemeEntryNumber = 0;
374         }
375
376         // Set the current theme as the summary text for the preference.
377         appThemePreference.setSummary(appThemeEntriesStringArray[appThemeEntryNumber]);
378
379         // Disable the WebView theme preference if the API >= 33 and the app theme is set to light.
380         webViewThemePreference.setEnabled((Build.VERSION.SDK_INT < 33) || (appThemeEntryNumber != 1));
381
382
383         // Get the WebView theme string arrays.
384         webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries);
385         webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values);
386
387         // Get the current WebView theme.
388         String currentWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value));
389
390         // Define a WebView theme entry number.
391         int webViewThemeEntryNumber;
392
393         // 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.
394         if (currentWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) {  // The light theme is selected.
395             // Store the WebView theme entry number.
396             webViewThemeEntryNumber = 1;
397         } else if (currentWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
398             // Store the WebView theme entry number.
399             webViewThemeEntryNumber = 2;
400         } else {  // The system default theme is selected.
401             // Store the WebView theme entry number.
402             webViewThemeEntryNumber = 0;
403         }
404
405         // Set the current theme as the summary text for the preference.
406         webViewThemePreference.setSummary(webViewThemeEntriesStringArray[webViewThemeEntryNumber]);
407
408
409         // Set the JavaScript icon.
410         if (javaScriptEnabled) {
411             javaScriptPreference.setIcon(R.drawable.javascript_enabled);
412         } else {
413             javaScriptPreference.setIcon(R.drawable.privacy_mode);
414         }
415
416         // Set the cookies icon.
417         if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false)) {
418             cookiesPreference.setIcon(R.drawable.cookies_enabled);
419         } else {
420             cookiesPreference.setIcon(R.drawable.cookies_disabled);
421         }
422
423         // Set the DOM storage icon.
424         if (javaScriptEnabled) {  // The preference is enabled.
425             if (sharedPreferences.getBoolean("dom_storage", false)) {  // DOM storage is enabled.
426                 domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
427             } else {  // DOM storage is disabled.
428                 domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
429             }
430         } else {  // The preference is disabled.  The icon should be ghosted.
431             domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
432         }
433
434         // Set the save form data icon if API < 26.  Save form data has no effect on API >= 26.
435         if (Build.VERSION.SDK_INT < 26) {
436             if (sharedPreferences.getBoolean("save_form_data", false))
437                 formDataPreference.setIcon(R.drawable.form_data_enabled);
438             else
439                 formDataPreference.setIcon(R.drawable.form_data_disabled);
440         }
441
442         // Set the custom user agent icon.
443         if (customUserAgentPreference.isEnabled())
444             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
445         else
446             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
447
448         // Set the X-Requested With header icon.
449         if (sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true))
450             xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_enabled);
451         else
452             xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_disabled);
453
454         // Set the incognito mode icon.
455         if (sharedPreferences.getBoolean("incognito_mode", false))
456             incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
457         else
458             incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
459
460         // Set the allow screenshots icon.
461         if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
462             allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled);
463         else
464             allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled);
465
466         // Set the EasyList icon.
467         if (sharedPreferences.getBoolean("easylist", true))
468             easyListPreference.setIcon(R.drawable.block_ads_enabled);
469         else
470             easyListPreference.setIcon(R.drawable.block_ads_disabled);
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         // Set the Fanboy lists icons.
479         if (fanboyAnnoyanceListEnabled) {
480             // Set the Fanboy annoyance list icon.
481             fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled);
482
483             // Set the Fanboy social blocking list icon.
484             fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted);
485         } else {
486             // Set the Fanboy annoyance list icon.
487             fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled);
488
489             // Set the Fanboy social blocking list icon.
490             if (fanboySocialBlockingEnabled) {
491                 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled);
492             } else {
493                 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled);
494             }
495         }
496
497         // Set the UltraList icon.
498         if (sharedPreferences.getBoolean("ultralist", true)){
499             ultraListPreference.setIcon(R.drawable.block_ads_enabled);
500         } else {
501             ultraListPreference.setIcon(R.drawable.block_ads_disabled);
502         }
503
504         // Set the UltraPrivacy icon.
505         if (sharedPreferences.getBoolean("ultraprivacy", true)) {
506             ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
507         } else {
508             ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
509         }
510
511         // Set the block all third-party requests icon.
512         if (sharedPreferences.getBoolean("block_all_third_party_requests", false)) {
513             blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled);
514         } else {
515             blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled);
516         }
517
518         // Set the Tracking Queries icon.
519         if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true)) {
520             trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled);
521         } else {
522             trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled);
523         }
524
525         // Set the AMP Redirects icon.
526         if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true)) {
527             ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled);
528         } else {
529             ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled);
530         }
531
532         // Set the search custom URL icon.
533         if (searchCustomURLPreference.isEnabled()) {
534             searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled);
535         } else {
536             searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted);
537         }
538
539         // Set the Proxy icons according to the theme and status.
540         if (proxyString.equals(ProxyHelper.NONE)) {  // Proxying is disabled.
541             // Set the main proxy icon to be disabled.
542             proxyPreference.setIcon(R.drawable.proxy_disabled);
543
544             // Set the custom proxy URL icon to be ghosted.
545             proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
546         } else {  // Proxying is enabled.
547             // Set the main proxy icon to be enabled.
548             proxyPreference.setIcon(R.drawable.proxy_enabled);
549
550             // Set the custom proxy URL icon according to its status.
551             if (proxyCustomUrlPreference.isEnabled()) {
552                 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled);
553             } else {
554                 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
555             }
556         }
557
558         // Set the full screen browsing mode icons.
559         if (fullScreenBrowsingMode) {  // Full screen browsing mode is enabled.
560             // Set the full screen browsing mode preference icon.
561             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
562
563             // Set the hide app bar icon.
564             if (sharedPreferences.getBoolean("hide_app_bar", true)) {
565                 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
566             } else {
567                 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
568             }
569         } else {  // Full screen browsing mode is disabled.
570             // Set the icons.
571             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
572             hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted);
573         }
574
575         // Set the clear everything preference icon.
576         if (clearEverything) {
577             clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
578         } else {
579             clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
580         }
581
582         // Set the clear cookies preference icon.
583         if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) {
584             clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
585         } else {
586             clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
587         }
588
589         // Set the clear DOM storage preference icon.
590         if (clearEverything || sharedPreferences.getBoolean("clear_dom_storage", true)) {
591             clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
592         } else {
593             clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
594         }
595
596         // Set the clear form data preference icon if the API < 26.  It has no effect on newer versions of Android.
597         if (Build.VERSION.SDK_INT < 26) {
598             if (clearEverything || sharedPreferences.getBoolean("clear_form_data", true)) {
599                 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
600             } else {
601                 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
602             }
603         }
604
605         // Set the clear logcat preference icon.
606         if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true)) {
607             clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
608         } else {
609             clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled);
610         }
611
612         // Set the clear cache preference icon.
613         if (clearEverything || sharedPreferences.getBoolean("clear_cache", true)) {
614             clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
615         } else {
616             clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
617         }
618
619         // Set the open intents in new tab preference icon.
620         if (sharedPreferences.getBoolean("open_intents_in_new_tab", true)) {
621             openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled);
622         } else {
623             openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled);
624         }
625
626         // Set the swipe to refresh preference icon.
627         if (sharedPreferences.getBoolean("swipe_to_refresh", true))
628             swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
629         else
630             swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
631
632         // Set the download with external app preference icon.
633         if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
634             downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled);
635         else
636             downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled);
637
638         // Set the scroll app bar preference icon.
639         if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
640             scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled);
641         else
642             scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled);
643
644         // Set the bottom app bar preference icon.
645         if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
646             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled);
647         else
648             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled);
649
650         // Set the display additional app bar icons preference icon.
651         if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
652             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
653         else
654             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
655
656         // Set the WebView theme preference icon.
657         if (webViewThemePreference.isEnabled()) {  // The WebView theme preference is enabled.
658             switch (webViewThemeEntryNumber) {
659                 case 0:  // The system default WebView theme is selected.
660                     // Get the current theme status.
661                     int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
662
663                     // Set the icon according to the app theme.
664                     if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
665                         webViewThemePreference.setIcon(R.drawable.webview_light_theme);
666                     else
667                         webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
668                     break;
669
670                 case 1:  // The light WebView theme is selected.
671                     // Set the icon.
672                     webViewThemePreference.setIcon(R.drawable.webview_light_theme);
673                     break;
674
675                 case 2:  // The dark WebView theme is selected.
676                     // Set the icon.
677                     webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
678                     break;
679             }
680         } else {  // The WebView theme preference is disabled.
681             webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted);
682         }
683
684         // Set the wide viewport preference icon.
685         if (sharedPreferences.getBoolean("wide_viewport", true)) {
686             wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled);
687         } else {
688             wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled);
689         }
690
691         // Set the display webpage images preference icon.
692         if (sharedPreferences.getBoolean("display_webpage_images", true)) {
693             displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
694         } else {
695             displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
696         }
697     }
698
699     // The listener should be unregistered when the app is paused.
700     @Override
701     public void onPause() {
702         // Run the default commands.
703         super.onPause();
704
705         // Get a handle for the shared preferences.
706         SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
707
708         // Remove the incorrect lint warning below that the shared preferences might be null.
709         assert sharedPreferences != null;
710
711         // Unregister the shared preference listener.
712         sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
713     }
714
715     // The listener should be re-registered when the app is resumed.
716     @Override
717     public void onResume() {
718         // Run the default commands.
719         super.onResume();
720
721         // Get a new shared preference change listener.
722         sharedPreferenceChangeListener = getSharedPreferenceChangeListener(requireContext());
723
724         // Get a handle for the shared preferences.
725         SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
726
727         // Remove the incorrect lint warning below that the shared preferences might be null.
728         assert sharedPreferences != null;
729
730         // Re-register the shared preference listener.
731         sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
732     }
733
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) -> {
739             switch (key) {
740                 case "javascript":
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);
745
746                         // Update the status of the DOM storage preference.
747                         domStoragePreference.setEnabled(true);
748
749                         // Update the icon for the DOM storage preference.
750                         if (sharedPreferences.getBoolean("dom_storage", false)) {
751                             domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
752                         } else {
753                             domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
754                         }
755                     } else {  // The JavaScript preference is disabled.
756                         // Update the icon for the JavaScript preference.
757                         javaScriptPreference.setIcon(R.drawable.privacy_mode);
758
759                         // Update the status of the DOM storage preference.
760                         domStoragePreference.setEnabled(false);
761
762                         // Set the icon for DOM storage preference to be ghosted.
763                         domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
764                     }
765                     break;
766
767                 case "cookies":
768                     // Update the icon.
769                     if (sharedPreferences.getBoolean(context.getString(R.string.cookies_key), false)) {
770                         cookiesPreference.setIcon(R.drawable.cookies_enabled);
771                     } else {
772                         cookiesPreference.setIcon(R.drawable.cookies_disabled);
773                     }
774                     break;
775
776                 case "dom_storage":
777                     // Update the icon.
778                     if (sharedPreferences.getBoolean("dom_storage", false)) {
779                         domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
780                     } else {
781                         domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
782                     }
783                     break;
784
785                 // Save form data can be removed once the minimum API >= 26.
786                 case "save_form_data":
787                     // Update the icon.
788                     if (sharedPreferences.getBoolean("save_form_data", false)) {
789                         formDataPreference.setIcon(R.drawable.form_data_enabled);
790                     } else {
791                         formDataPreference.setIcon(R.drawable.form_data_disabled);
792                     }
793                     break;
794
795                 case "user_agent":
796                     // Get the new user agent name.
797                     String newUserAgentName = sharedPreferences.getString("user_agent", context.getString(R.string.user_agent_default_value));
798
799                     // Get the array position for the new user agent name.
800                     int newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName);
801
802                     // Get the translated new user agent name.
803                     String translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition];
804
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);
810
811                             // Disable the custom user agent preference.
812                             customUserAgentPreference.setEnabled(false);
813
814                             // Set the custom user agent preference icon.
815                             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
816                             break;
817
818                         case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
819                             // Set the summary text.
820                             userAgentPreference.setSummary(R.string.custom_user_agent);
821
822                             // Enable the custom user agent preference.
823                             customUserAgentPreference.setEnabled(true);
824
825                             // Set the custom user agent preference icon.
826                             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
827                             break;
828
829                         default:
830                             // Get the user agent summary from the user agent data array.
831                             userAgentPreference.setSummary(translatedNewUserAgentName + ":\n" + userAgentDataArray[newUserAgentArrayPosition]);
832
833                             // Disable the custom user agent preference.
834                             customUserAgentPreference.setEnabled(false);
835
836                             // Set the custom user agent preference icon.
837                             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
838                     }
839                     break;
840
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)));
844                     break;
845
846                 case "x_requested_with_header":
847                     // Update the icon.
848                     if (sharedPreferences.getBoolean(context.getString(R.string.x_requested_with_header_key), true))
849                         xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_enabled);
850                     else
851                         xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_disabled);
852
853                     // Restart Privacy Browser.
854                     restartPrivacyBrowser();
855                     break;
856
857                 case "incognito_mode":
858                     // Update the icon.
859                     if (sharedPreferences.getBoolean("incognito_mode", false))
860                         incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
861                     else
862                         incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
863                     break;
864
865                 case "allow_screenshots":
866                     // Update the icon.
867                     if (sharedPreferences.getBoolean(context.getString(R.string.allow_screenshots_key), false))
868                         allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled);
869                     else
870                         allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled);
871
872                     // Restart Privacy Browser.
873                     restartPrivacyBrowser();
874                     break;
875
876                 case "easylist":
877                     // Update the icon.
878                     if (sharedPreferences.getBoolean("easylist", true))
879                         easyListPreference.setIcon(R.drawable.block_ads_enabled);
880                     else
881                         easyListPreference.setIcon(R.drawable.block_ads_disabled);
882                     break;
883
884                 case "easyprivacy":
885                     // Update the icon.
886                     if (sharedPreferences.getBoolean("easyprivacy", true))
887                         easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
888                     else
889                         easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
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 "tracking_queries":
956                     // Update the icon.
957                     if (sharedPreferences.getBoolean(context.getString(R.string.tracking_queries_key), true)) {
958                         trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled);
959                     } else {
960                         trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled);
961                     }
962                     break;
963
964                 case "amp_redirects":
965                     // Update the icon.
966                     if (sharedPreferences.getBoolean(context.getString(R.string.amp_redirects_key), true)) {
967                         ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled);
968                     } else {
969                         ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled);
970                     }
971                     break;
972
973                 case "search":
974                     // Store the new search string.
975                     String newSearchString = sharedPreferences.getString("search", context.getString(R.string.search_default_value));
976
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);
981
982                         // Enable the search custom URL preference.
983                         searchCustomURLPreference.setEnabled(true);
984
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);
990
991                         // Disable `searchCustomURLPreference`.
992                         searchCustomURLPreference.setEnabled(false);
993
994                         // Set the search custom URL preference icon.
995                         searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted);
996                     }
997                     break;
998
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)));
1002                     break;
1003
1004                 case "proxy":
1005                     // Get current proxy string.
1006                     String currentProxyString = sharedPreferences.getString("proxy", context.getString(R.string.proxy_default_value));
1007
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));
1012                             break;
1013
1014                         case ProxyHelper.TOR:
1015                             proxyPreference.setSummary(context.getString(R.string.tor_enabled));
1016                             break;
1017
1018                         case ProxyHelper.I2P:
1019                             proxyPreference.setSummary(context.getString(R.string.i2p_enabled));
1020                             break;
1021
1022                         case ProxyHelper.CUSTOM:
1023                             proxyPreference.setSummary(context.getString(R.string.custom_proxy));
1024                             break;
1025                     }
1026
1027                     // Update the status of the custom URL preference.
1028                     proxyCustomUrlPreference.setEnabled(currentProxyString.equals(ProxyHelper.CUSTOM));
1029
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);
1034
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);
1040
1041                         /// Set the custom proxy URL icon according to its status.
1042                         if (proxyCustomUrlPreference.isEnabled()) {
1043                             proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled);
1044                         } else {
1045                             proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
1046                         }
1047                     }
1048                     break;
1049
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)));
1053                     break;
1054
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);
1059
1060                         // Set the hide app bar preference icon.
1061                         if (sharedPreferences.getBoolean("hide_app_bar", true)) {
1062                             hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1063                         } else {
1064                             hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1065                         }
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);
1070                     }
1071                     break;
1072
1073                 case "hide_app_bar":
1074                     // Update the icon.
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);
1080                     }
1081                     break;
1082
1083                 case "clear_everything":
1084                     // Store the new clear everything status
1085                     boolean newClearEverythingBoolean = sharedPreferences.getBoolean("clear_everything", true);
1086
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);
1093
1094                     // Update the clear everything preference icon.
1095                     if (newClearEverythingBoolean) {
1096                         clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
1097                     } else {
1098                         clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
1099                     }
1100
1101                     // Update the clear cookies preference icon.
1102                     if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cookies", true)) {
1103                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
1104                     } else {
1105                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
1106                     }
1107
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);
1111                     } else {
1112                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
1113                     }
1114
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);
1119                         } else {
1120                             clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
1121                         }
1122                     }
1123
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);
1127                     } else {
1128                         clearLogcatPreference.setIcon(R.drawable.clear_cache_disabled);
1129                     }
1130
1131                     // Update the clear cache preference icon.
1132                     if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cache", true)) {
1133                         clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
1134                     } else {
1135                         clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
1136                     }
1137                     break;
1138
1139                 case "clear_cookies":
1140                     // Update the icon.
1141                     if (sharedPreferences.getBoolean("clear_cookies", true)) {
1142                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
1143                     } else {
1144                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
1145                     }
1146                     break;
1147
1148                 case "clear_dom_storage":
1149                     // Update the icon.
1150                     if (sharedPreferences.getBoolean("clear_dom_storage", true)) {
1151                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
1152                     } else {
1153                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
1154                     }
1155                     break;
1156
1157                 // This section can be removed once the minimum API >= 26.
1158                 case "clear_form_data":
1159                     // Update the icon.
1160                     if (sharedPreferences.getBoolean("clear_form_data", true)) {
1161                         clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
1162                     } else {
1163                         clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
1164                     }
1165                     break;
1166
1167                 case "clear_logcat":
1168                     // Update the icon.
1169                     if (sharedPreferences.getBoolean(context.getString(R.string.clear_logcat_key), true)) {
1170                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
1171                     } else {
1172                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled);
1173                     }
1174                     break;
1175
1176                 case "clear_cache":
1177                     // Update the icon.
1178                     if (sharedPreferences.getBoolean("clear_cache", true)) {
1179                         clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
1180                     } else {
1181                         clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
1182                     }
1183                     break;
1184
1185                 case "homepage":
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)));
1188                     break;
1189
1190                 case "font_size":
1191                     // Update the font size summary text.
1192                     fontSizePreference.setSummary(sharedPreferences.getString("font_size", context.getString(R.string.font_size_default_value)) + "%");
1193                     break;
1194
1195                 case "open_intents_in_new_tab":
1196                     // Update the icon.
1197                     if (sharedPreferences.getBoolean("open_intents_in_new_tab", true))
1198                         openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled);
1199                     else
1200                         openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled);
1201                     break;
1202
1203                 case "swipe_to_refresh":
1204                     // Update the icon.
1205                     if (sharedPreferences.getBoolean("swipe_to_refresh", true))
1206                         swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
1207                     else
1208                         swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
1209                     break;
1210
1211                 case "download_with_external_app":
1212                     // Update the icon.
1213                     if (sharedPreferences.getBoolean(context.getString(R.string.download_with_external_app_key), false))
1214                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled);
1215                     else
1216                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled);
1217                     break;
1218
1219                 case "scroll_app_bar":
1220                     // Update the icon.
1221                     if (sharedPreferences.getBoolean(context.getString(R.string.scroll_app_bar_key), true))
1222                         scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1223                     else
1224                         scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1225
1226                     break;
1227
1228                 case "bottom_app_bar":
1229                     // Update the icon.
1230                     if (sharedPreferences.getBoolean(context.getString(R.string.bottom_app_bar_key), false))
1231                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled);
1232                     else
1233                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled);
1234
1235                     // Restart Privacy Browser.
1236                     restartPrivacyBrowser();
1237                     break;
1238
1239                 case "display_additional_app_bar_icons":
1240                     // Update the icon.
1241                     if (sharedPreferences.getBoolean(context.getString(R.string.display_additional_app_bar_icons_key), false))
1242                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
1243                     else
1244                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
1245                     break;
1246
1247                 case "app_theme":
1248                     // Get the new theme.
1249                     String newAppTheme = sharedPreferences.getString("app_theme", context.getString(R.string.app_theme_default_value));
1250
1251                     // Declare an app theme entry number.
1252                     int appThemeEntryNumber;
1253
1254                     // 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.
1255                     if (newAppTheme.equals(appThemeEntryValuesStringArray[1])) {  // The light theme is selected.
1256                         // Store the app theme entry number.
1257                         appThemeEntryNumber = 1;
1258                     } else if (newAppTheme.equals(appThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
1259                         // Store the app theme entry number.
1260                         appThemeEntryNumber = 2;
1261                     } else {  // The system default theme is selected.
1262                         // Store the app theme entry number.
1263                         appThemeEntryNumber = 0;
1264                     }
1265
1266                     // 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.
1267                     switch (appThemeEntryNumber) {
1268                         case 0:  // The system default theme is selected.
1269                             // Update the theme preference summary text.
1270                             appThemePreference.setSummary(appThemeEntriesStringArray[0]);
1271
1272                             // Apply the new theme.
1273                             if (Build.VERSION.SDK_INT >= 28) {  // The system default theme is supported.
1274                                 // Follow the system default theme.
1275                                 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
1276                             } else {// The system default theme is not supported.
1277                                 // Follow the battery saver mode.
1278                                 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
1279                             }
1280                             break;
1281
1282                         case 1:  // The light theme is selected.
1283                             // Update the theme preference summary text.
1284                             appThemePreference.setSummary(appThemeEntriesStringArray[1]);
1285
1286                             // Apply the new theme.
1287                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
1288                             break;
1289
1290                         case 2:
1291                             // Update the theme preference summary text.
1292                             appThemePreference.setSummary(appThemeEntriesStringArray[2]);
1293
1294                             // Apply the new theme.
1295                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
1296                             break;
1297                     }
1298
1299                     // Disable the WebView theme preference if the API >= 33 and the app theme is set to light.
1300                     webViewThemePreference.setEnabled((Build.VERSION.SDK_INT < 33) || (appThemeEntryNumber != 1));
1301
1302                     // Get the WebView theme.
1303                     String webViewTheme = sharedPreferences.getString("webview_theme", context.getString(R.string.webview_theme_default_value));
1304
1305                     // Declare a WebView theme entry number.
1306                     int webViewThemeEntryNumber;
1307
1308                     // 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.
1309                     if (webViewTheme.equals(webViewThemeEntriesStringArray[1])) {  // The light theme is selected.
1310                         // Store the WebView theme entry number.
1311                         webViewThemeEntryNumber = 1;
1312                     } else if (webViewTheme.equals(webViewThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
1313                         // Store the WebView theme entry number.
1314                         webViewThemeEntryNumber = 2;
1315                     } else {  // The system default theme is selected.
1316                         // Store the WebView theme entry number.
1317                         webViewThemeEntryNumber = 0;
1318                     }
1319
1320                     // Update the WebView theme preference icon.
1321                     if (webViewThemePreference.isEnabled()) {  // The WebView theme preference is enabled.
1322                         switch (webViewThemeEntryNumber) {
1323                             case 0:  // The system default WebView theme is selected.
1324                                 // Get the current theme status.
1325                                 int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
1326
1327                                 // Set the icon according to the app theme.
1328                                 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1329                                     webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1330                                 else
1331                                     webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1332                                 break;
1333
1334                             case 1:  // The light WebView theme is selected.
1335                                 // Set the icon.
1336                                 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1337                                 break;
1338
1339                             case 2:  // The dark WebView theme is selected.
1340                                 // Set the icon.
1341                                 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1342                                 break;
1343                         }
1344                     } else {  // The WebView theme preference is disabled.
1345                         webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted);
1346                     }
1347                     break;
1348
1349                 case "webview_theme":
1350                     // Get the new WebView theme.
1351                     String newWebViewTheme = sharedPreferences.getString("webview_theme", context.getString(R.string.webview_theme_default_value));
1352
1353                     // Declare a new WebView theme entry number.
1354                     int newWebViewThemeEntryNumber;
1355
1356                     // 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.
1357                     if (newWebViewTheme.equals(webViewThemeEntriesStringArray[1])) {  // The light theme is selected.
1358                         // Store the new WebView theme entry number.
1359                         newWebViewThemeEntryNumber = 1;
1360                     } else if (newWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
1361                         // Store the new WebView theme entry number.
1362                         newWebViewThemeEntryNumber = 2;
1363                     } else {  // The system default theme is selected.
1364                         // Store the new WebView theme entry number.
1365                         newWebViewThemeEntryNumber = 0;
1366                     }
1367
1368                     // Update the icon.
1369                     switch (newWebViewThemeEntryNumber) {
1370                         case 0:  // The system default WebView theme is selected.
1371                             // Get the current theme status.
1372                             int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
1373
1374                             // Set the icon.
1375                             if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1376                                 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1377                             } else {
1378                                 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1379                             }
1380                             break;
1381
1382                         case 1:  // The light theme is selected.
1383                             // Set the icon.
1384                             webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1385                             break;
1386
1387                         case 2:  // The dark theme is selected.
1388                             // Set the icon.
1389                             webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1390                             break;
1391                     }
1392
1393                     // Set the current theme as the summary text for the preference.
1394                     webViewThemePreference.setSummary(webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]);
1395                     break;
1396
1397                 case "wide_viewport":
1398                     // Update the icon.
1399                     if (sharedPreferences.getBoolean("wide_viewport", true)) {
1400                         wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled);
1401                     } else {
1402                         wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled);
1403                     }
1404                     break;
1405
1406                 case "display_webpage_images":
1407                     // Update the icon.
1408                     if (sharedPreferences.getBoolean("display_webpage_images", true)) {
1409                         displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
1410                     } else {
1411                         displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
1412                     }
1413                     break;
1414             }
1415         };
1416     }
1417
1418     private void restartPrivacyBrowser() {
1419         // Create an intent to restart Privacy Browser.
1420         Intent restartIntent = requireActivity().getParentActivityIntent();
1421
1422         // Assert that the intent is not null to remove the lint error below.
1423         assert restartIntent != null;
1424
1425         // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack.  It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1426         restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1427
1428         // Create a handler to restart the activity.
1429         Handler restartHandler = new Handler(Looper.getMainLooper());
1430
1431         // Create a runnable to restart the activity.
1432         Runnable restartRunnable = () -> {
1433             // Restart the activity.
1434             startActivity(restartIntent);
1435
1436             // Kill this instance of Privacy Browser.  Otherwise, the app exhibits sporadic behavior after the restart.
1437             System.exit(0);
1438         };
1439
1440         // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1441         restartHandler.postDelayed(restartRunnable, 400);
1442     }
1443 }