]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java
Add X-Requested-With settings. https://redmine.stoutner.com/issues/819
[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 xRequestedWithHeaderPreference;
70     private Preference incognitoModePreference;
71     private Preference allowScreenshotsPreference;
72     private Preference easyListPreference;
73     private Preference easyPrivacyPreference;
74     private Preference fanboyAnnoyanceListPreference;
75     private Preference fanboySocialBlockingListPreference;
76     private Preference ultraListPreference;
77     private Preference ultraPrivacyPreference;
78     private Preference blockAllThirdPartyRequestsPreference;
79     private Preference trackingQueriesPreference;
80     private Preference ampRedirectsPreference;
81     private Preference searchPreference;
82     private Preference searchCustomURLPreference;
83     private Preference proxyPreference;
84     private Preference proxyCustomUrlPreference;
85     private Preference fullScreenBrowsingModePreference;
86     private Preference hideAppBarPreference;
87     private Preference clearEverythingPreference;
88     private Preference clearCookiesPreference;
89     private Preference clearDomStoragePreference;
90     private Preference clearFormDataPreference;  // The clear form data preference can be removed once the minimum API >= 26.
91     private Preference clearLogcatPreference;
92     private Preference clearCachePreference;
93     private Preference homepagePreference;
94     private Preference fontSizePreference;
95     private Preference openIntentsInNewTabPreference;
96     private Preference swipeToRefreshPreference;
97     private Preference downloadWithExternalAppPreference;
98     private Preference scrollAppBarPreference;
99     private Preference bottomAppBarPreference;
100     private Preference displayAdditionalAppBarIconsPreference;
101     private Preference appThemePreference;
102     private Preference webViewThemePreference;
103     private Preference wideViewportPreference;
104     private Preference displayWebpageImagesPreference;
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         xRequestedWithHeaderPreference = findPreference(getString(R.string.x_requested_with_header_key));
137         incognitoModePreference = findPreference("incognito_mode");
138         allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key));
139         easyListPreference = findPreference("easylist");
140         easyPrivacyPreference = findPreference("easyprivacy");
141         fanboyAnnoyanceListPreference = findPreference("fanboys_annoyance_list");
142         fanboySocialBlockingListPreference = findPreference("fanboys_social_blocking_list");
143         ultraListPreference = findPreference("ultralist");
144         ultraPrivacyPreference = findPreference("ultraprivacy");
145         blockAllThirdPartyRequestsPreference = findPreference("block_all_third_party_requests");
146         trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key));
147         ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key));
148         searchPreference = findPreference("search");
149         searchCustomURLPreference = findPreference("search_custom_url");
150         proxyPreference = findPreference("proxy");
151         proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key));
152         fullScreenBrowsingModePreference = findPreference("full_screen_browsing_mode");
153         hideAppBarPreference = findPreference("hide_app_bar");
154         clearEverythingPreference = findPreference("clear_everything");
155         clearCookiesPreference = findPreference("clear_cookies");
156         clearDomStoragePreference = findPreference("clear_dom_storage");
157         clearFormDataPreference = findPreference("clear_form_data");  // The clear form data preference can be removed once the minimum API >= 26.
158         clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key));
159         clearCachePreference = findPreference("clear_cache");
160         homepagePreference = findPreference("homepage");
161         fontSizePreference = findPreference("font_size");
162         openIntentsInNewTabPreference = findPreference("open_intents_in_new_tab");
163         swipeToRefreshPreference = findPreference("swipe_to_refresh");
164         downloadWithExternalAppPreference = findPreference(getString(R.string.download_with_external_app_key));
165         scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key));
166         bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key));
167         displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key));
168         appThemePreference = findPreference("app_theme");
169         webViewThemePreference = findPreference("webview_theme");
170         wideViewportPreference = findPreference("wide_viewport");
171         displayWebpageImagesPreference = findPreference("display_webpage_images");
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 xRequestedWithHeaderPreference != null;
181         assert incognitoModePreference != null;
182         assert allowScreenshotsPreference != null;
183         assert easyListPreference != null;
184         assert easyPrivacyPreference != null;
185         assert fanboyAnnoyanceListPreference != null;
186         assert fanboySocialBlockingListPreference != null;
187         assert ultraListPreference != null;
188         assert ultraPrivacyPreference != null;
189         assert blockAllThirdPartyRequestsPreference != null;
190         assert trackingQueriesPreference != null;
191         assert ampRedirectsPreference != null;
192         assert searchPreference != null;
193         assert searchCustomURLPreference != null;
194         assert proxyPreference != null;
195         assert proxyCustomUrlPreference != null;
196         assert fullScreenBrowsingModePreference != null;
197         assert hideAppBarPreference != null;
198         assert clearEverythingPreference != null;
199         assert clearCookiesPreference != null;
200         assert clearDomStoragePreference != null;
201         assert clearFormDataPreference != null;
202         assert clearLogcatPreference != null;
203         assert clearCachePreference != null;
204         assert homepagePreference != null;
205         assert fontSizePreference != null;
206         assert openIntentsInNewTabPreference != null;
207         assert swipeToRefreshPreference != null;
208         assert downloadWithExternalAppPreference != null;
209         assert scrollAppBarPreference != null;
210         assert bottomAppBarPreference != null;
211         assert displayAdditionalAppBarIconsPreference != null;
212         assert appThemePreference != null;
213         assert webViewThemePreference != null;
214         assert wideViewportPreference != null;
215         assert displayWebpageImagesPreference != null;
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         // Set the custom user agent icon.
444         if (customUserAgentPreference.isEnabled())
445             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
446         else
447             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
448
449         // Set the X-Requested With header icon.
450         if (sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true))
451             xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_enabled);
452         else
453             xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_disabled);
454
455         // Set the incognito mode icon.
456         if (sharedPreferences.getBoolean("incognito_mode", false))
457             incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
458         else
459             incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
460
461         // Set the allow screenshots icon.
462         if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
463             allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled);
464         else
465             allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled);
466
467         // Set the EasyList icon.
468         if (sharedPreferences.getBoolean("easylist", true))
469             easyListPreference.setIcon(R.drawable.block_ads_enabled);
470         else
471             easyListPreference.setIcon(R.drawable.block_ads_disabled);
472
473         // Set the EasyPrivacy icon.
474         if (sharedPreferences.getBoolean("easyprivacy", true))
475             easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
476         else
477             easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
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 Tracking Queries icon.
520         if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true)) {
521             trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled);
522         } else {
523             trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled);
524         }
525
526         // Set the AMP Redirects icon.
527         if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true)) {
528             ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled);
529         } else {
530             ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled);
531         }
532
533         // Set the search custom URL icon.
534         if (searchCustomURLPreference.isEnabled()) {
535             searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled);
536         } else {
537             searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted);
538         }
539
540         // Set the Proxy icons according to the theme and status.
541         if (proxyString.equals(ProxyHelper.NONE)) {  // Proxying is disabled.
542             // Set the main proxy icon to be disabled.
543             proxyPreference.setIcon(R.drawable.proxy_disabled);
544
545             // Set the custom proxy URL icon to be ghosted.
546             proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
547         } else {  // Proxying is enabled.
548             // Set the main proxy icon to be enabled.
549             proxyPreference.setIcon(R.drawable.proxy_enabled);
550
551             // Set the custom proxy URL icon according to its status.
552             if (proxyCustomUrlPreference.isEnabled()) {
553                 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled);
554             } else {
555                 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
556             }
557         }
558
559         // Set the full screen browsing mode icons.
560         if (fullScreenBrowsingMode) {  // Full screen browsing mode is enabled.
561             // Set the full screen browsing mode preference icon.
562             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
563
564             // Set the hide app bar icon.
565             if (sharedPreferences.getBoolean("hide_app_bar", true)) {
566                 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
567             } else {
568                 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
569             }
570         } else {  // Full screen browsing mode is disabled.
571             // Set the icons.
572             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
573             hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted);
574         }
575
576         // Set the clear everything preference icon.
577         if (clearEverything) {
578             clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
579         } else {
580             clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
581         }
582
583         // Set the clear cookies preference icon.
584         if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) {
585             clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
586         } else {
587             clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
588         }
589
590         // Set the clear DOM storage preference icon.
591         if (clearEverything || sharedPreferences.getBoolean("clear_dom_storage", true)) {
592             clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
593         } else {
594             clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
595         }
596
597         // Set the clear form data preference icon if the API < 26.  It has no effect on newer versions of Android.
598         if (Build.VERSION.SDK_INT < 26) {
599             if (clearEverything || sharedPreferences.getBoolean("clear_form_data", true)) {
600                 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
601             } else {
602                 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
603             }
604         }
605
606         // Set the clear logcat preference icon.
607         if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true)) {
608             clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
609         } else {
610             clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled);
611         }
612
613         // Set the clear cache preference icon.
614         if (clearEverything || sharedPreferences.getBoolean("clear_cache", true)) {
615             clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
616         } else {
617             clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
618         }
619
620         // Set the open intents in new tab preference icon.
621         if (sharedPreferences.getBoolean("open_intents_in_new_tab", true)) {
622             openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled);
623         } else {
624             openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled);
625         }
626
627         // Set the swipe to refresh preference icon.
628         if (sharedPreferences.getBoolean("swipe_to_refresh", true)) {
629             swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
630         } else {
631             swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
632         }
633
634         // Set the download with external app preference icon.
635         if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false)) {
636             downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled);
637         } else {
638             downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled);
639         }
640
641         // Set the scroll app bar preference icon.
642         if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true)) {
643             scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled);
644         } else {
645             scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled);
646         }
647
648         // Set the bottom app bar preference icon.
649         if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
650             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled);
651         } else {
652             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled);
653         }
654
655         // Set the display additional app bar icons preference icon.
656         if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false)) {
657             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
658         } else {
659             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
660         }
661
662         // Set the WebView theme preference icon.
663         switch (webViewThemeEntryNumber) {
664             case 0:  // The system default WebView theme is selected.
665                 // Set the icon according to the app theme.
666                 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
667                     webViewThemePreference.setIcon(R.drawable.webview_light_theme);
668                 } else {
669                     webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
670                 }
671                 break;
672
673             case 1:  // The light WebView theme is selected.
674                 // Set the icon.
675                 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
676                 break;
677
678             case 2:  // The dark WebView theme is selected.
679                 // Set the icon.
680                 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
681                 break;
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                     }
1202                     break;
1203
1204                 case "swipe_to_refresh":
1205                     // Update the icon.
1206                     if (sharedPreferences.getBoolean("swipe_to_refresh", true)) {
1207                         swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
1208                     } else {
1209                         swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
1210                     }
1211                     break;
1212
1213                 case "download_with_external_app":
1214                     // Update the icon.
1215                     if (sharedPreferences.getBoolean(context.getString(R.string.download_with_external_app_key), false)) {
1216                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled);
1217                     } else {
1218                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled);
1219                     }
1220                     break;
1221
1222                 case "scroll_app_bar":
1223                     // Update the icon.
1224                     if (sharedPreferences.getBoolean(context.getString(R.string.scroll_app_bar_key), true)) scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1225                     else scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1226
1227                     break;
1228
1229                 case "bottom_app_bar":
1230                     // Update the icon.
1231                     if (sharedPreferences.getBoolean(context.getString(R.string.bottom_app_bar_key), false)) bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled);
1232                     else bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled);
1233
1234                     // Restart Privacy Browser.
1235                     restartPrivacyBrowser();
1236                     break;
1237
1238                 case "display_additional_app_bar_icons":
1239                     // Update the icon.
1240                     if (sharedPreferences.getBoolean(context.getString(R.string.display_additional_app_bar_icons_key), false)) {
1241                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
1242                     } else {
1243                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
1244                     }
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                     // Update the system according to the new theme.  A switch statement cannot be used because the theme entry values string array is not a compile-time constant.
1252                     if (newAppTheme.equals(appThemeEntryValuesStringArray[1])) {  // The light theme is selected.
1253                         // Update the theme preference summary text.
1254                         appThemePreference.setSummary(appThemeEntriesStringArray[1]);
1255
1256                         // Apply the new theme.
1257                         AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
1258                     } else if (newAppTheme.equals(appThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
1259                         // Update the theme preference summary text.
1260                         appThemePreference.setSummary(appThemeEntriesStringArray[2]);
1261
1262                         // Apply the new theme.
1263                         AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
1264                     } else {  // The system default theme is selected.
1265                         // Update the theme preference summary text.
1266                         appThemePreference.setSummary(appThemeEntriesStringArray[0]);
1267
1268                         // Apply the new theme.
1269                         if (Build.VERSION.SDK_INT >= 28) {  // The system default theme is supported.
1270                             // Follow the system default theme.
1271                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
1272                         } else {// The system default theme is not supported.
1273                             // Follow the battery saver mode.
1274                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
1275                         }
1276                     }
1277
1278                     // Update the current theme status.
1279                     currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
1280                     break;
1281
1282                 case "webview_theme":
1283                     // Get the new WebView theme.
1284                     String newWebViewTheme = sharedPreferences.getString("webview_theme", context.getString(R.string.webview_theme_default_value));
1285
1286                     // Define a new WebView theme entry number.
1287                     int newWebViewThemeEntryNumber;
1288
1289                     // Get the webView theme entry number that matches the new WebView theme.  A switch statement cannot be used because the theme entry values string array is not a compile time constant.
1290                     if (newWebViewTheme.equals(webViewThemeEntriesStringArray[1])) {  // The light theme is selected.
1291                         // Store the new WebView theme entry number.
1292                         newWebViewThemeEntryNumber = 1;
1293                     } else if (newWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
1294                         // Store the WebView theme entry number.
1295                         newWebViewThemeEntryNumber = 2;
1296                     } else {  // The system default theme is selected.
1297                         // Store the WebView theme entry number.
1298                         newWebViewThemeEntryNumber = 0;
1299                     }
1300
1301                     // Update the icon.
1302                     switch (newWebViewThemeEntryNumber) {
1303                         case 0:  // The system default WebView theme is selected.
1304                             // Set the icon.
1305                             if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1306                                 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1307                             } else {
1308                                 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1309                             }
1310                             break;
1311
1312                         case 1:  // The light theme is selected.
1313                             // Set the icon.
1314                             webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1315                             break;
1316
1317                         case 2:  // The dark theme is selected.
1318                             // Set the icon.
1319                             webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1320                             break;
1321                     }
1322
1323                     // Set the current theme as the summary text for the preference.
1324                     webViewThemePreference.setSummary(webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]);
1325                     break;
1326
1327                 case "wide_viewport":
1328                     // Update the icon.
1329                     if (sharedPreferences.getBoolean("wide_viewport", true)) {
1330                         wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled);
1331                     } else {
1332                         wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled);
1333                     }
1334                     break;
1335
1336                 case "display_webpage_images":
1337                     // Update the icon.
1338                     if (sharedPreferences.getBoolean("display_webpage_images", true)) {
1339                         displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
1340                     } else {
1341                         displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
1342                     }
1343                     break;
1344             }
1345         };
1346     }
1347
1348     private void restartPrivacyBrowser() {
1349         // Create an intent to restart Privacy Browser.
1350         Intent restartIntent = requireActivity().getParentActivityIntent();
1351
1352         // Assert that the intent is not null to remove the lint error below.
1353         assert restartIntent != null;
1354
1355         // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack.  It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1356         restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1357
1358         // Create a handler to restart the activity.
1359         Handler restartHandler = new Handler(Looper.getMainLooper());
1360
1361         // Create a runnable to restart the activity.
1362         Runnable restartRunnable = () -> {
1363             // Restart the activity.
1364             startActivity(restartIntent);
1365
1366             // Kill this instance of Privacy Browser.  Otherwise, the app exhibits sporadic behavior after the restart.
1367             System.exit(0);
1368         };
1369
1370         // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1371         restartHandler.postDelayed(restartRunnable, 400);
1372     }
1373 }