]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java
Standardize the app bar icon size. https://redmine.stoutner.com/issues/877
[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                     break;
853
854                 case "incognito_mode":
855                     // Update the icon.
856                     if (sharedPreferences.getBoolean("incognito_mode", false))
857                         incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
858                     else
859                         incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
860                     break;
861
862                 case "allow_screenshots":
863                     // Update the icon.
864                     if (sharedPreferences.getBoolean(context.getString(R.string.allow_screenshots_key), false))
865                         allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled);
866                     else
867                         allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled);
868
869                     // Restart Privacy Browser.
870                     restartPrivacyBrowser();
871                     break;
872
873                 case "easylist":
874                     // Update the icon.
875                     if (sharedPreferences.getBoolean("easylist", true))
876                         easyListPreference.setIcon(R.drawable.block_ads_enabled);
877                     else
878                         easyListPreference.setIcon(R.drawable.block_ads_disabled);
879                     break;
880
881                 case "easyprivacy":
882                     // Update the icon.
883                     if (sharedPreferences.getBoolean("easyprivacy", true))
884                         easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
885                     else
886                         easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
887                     break;
888
889                 case "fanboys_annoyance_list":
890                     boolean currentFanboyAnnoyanceList = sharedPreferences.getBoolean("fanboys_annoyance_list", true);
891                     boolean currentFanboySocialBlockingList = sharedPreferences.getBoolean("fanboys_social_blocking_list", true);
892
893                     // Update the Fanboy icons.
894                     if (currentFanboyAnnoyanceList) {  // Fanboy's annoyance list is enabled.
895                         // Update the Fanboy's annoyance list icon.
896                         fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled);
897
898                         // Update the Fanboy's social blocking list icon.
899                         fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted);
900                     } else {  // Fanboy's annoyance list is disabled.
901                         // Update the Fanboy's annoyance list icon.
902                         fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled);
903
904                         // Update the Fanboy's social blocking list icon.
905                         if (currentFanboySocialBlockingList) {
906                             fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled);
907                         } else {
908                             fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled);
909                         }
910                     }
911
912                     // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
913                     fanboySocialBlockingListPreference.setEnabled(!currentFanboyAnnoyanceList);
914                     break;
915
916                 case "fanboys_social_blocking_list":
917                     // Update the icon.
918                     if (sharedPreferences.getBoolean("fanboys_social_blocking_list", true)) {
919                         fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled);
920                     } else {
921                         fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled);
922                     }
923                     break;
924
925                 case "ultralist":
926                     // Update the icon.
927                     if (sharedPreferences.getBoolean("ultralist", true)) {
928                         ultraListPreference.setIcon(R.drawable.block_ads_enabled);
929                     } else {
930                         ultraListPreference.setIcon(R.drawable.block_ads_disabled);
931                     }
932                     break;
933
934                 case "ultraprivacy":
935                     // Update the icon.
936                     if (sharedPreferences.getBoolean("ultraprivacy", true)) {
937                         ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled);
938                     } else {
939                         ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled);
940                     }
941                     break;
942
943                 case "block_all_third_party_requests":
944                     // Update the icon.
945                     if (sharedPreferences.getBoolean("block_all_third_party_requests", false)) {
946                         blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled);
947                     } else {
948                         blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled);
949                     }
950                     break;
951
952                 case "tracking_queries":
953                     // Update the icon.
954                     if (sharedPreferences.getBoolean(context.getString(R.string.tracking_queries_key), true)) {
955                         trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled);
956                     } else {
957                         trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled);
958                     }
959                     break;
960
961                 case "amp_redirects":
962                     // Update the icon.
963                     if (sharedPreferences.getBoolean(context.getString(R.string.amp_redirects_key), true)) {
964                         ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled);
965                     } else {
966                         ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled);
967                     }
968                     break;
969
970                 case "search":
971                     // Store the new search string.
972                     String newSearchString = sharedPreferences.getString("search", context.getString(R.string.search_default_value));
973
974                     // Update the search and search custom URL preferences.
975                     if (newSearchString.equals("Custom URL")) {  // `Custom URL` is selected.
976                         // Set the summary text to `R.string.custom_url`, which is translated.
977                         searchPreference.setSummary(R.string.custom_url);
978
979                         // Enable the search custom URL preference.
980                         searchCustomURLPreference.setEnabled(true);
981
982                         // Set the search custom URL preference icon.
983                         searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled);
984                     } else {  // `Custom URL` is not selected.
985                         // Set the summary text to `newSearchString`.
986                         searchPreference.setSummary(newSearchString);
987
988                         // Disable `searchCustomURLPreference`.
989                         searchCustomURLPreference.setEnabled(false);
990
991                         // Set the search custom URL preference icon.
992                         searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted);
993                     }
994                     break;
995
996                 case "search_custom_url":
997                     // Set the new search custom URL as the summary text for the preference.
998                     searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", context.getString(R.string.search_custom_url_default_value)));
999                     break;
1000
1001                 case "proxy":
1002                     // Get current proxy string.
1003                     String currentProxyString = sharedPreferences.getString("proxy", context.getString(R.string.proxy_default_value));
1004
1005                     // Update the summary text for the proxy preference.
1006                     switch (currentProxyString) {
1007                         case ProxyHelper.NONE:
1008                             proxyPreference.setSummary(context.getString(R.string.no_proxy_enabled));
1009                             break;
1010
1011                         case ProxyHelper.TOR:
1012                             proxyPreference.setSummary(context.getString(R.string.tor_enabled));
1013                             break;
1014
1015                         case ProxyHelper.I2P:
1016                             proxyPreference.setSummary(context.getString(R.string.i2p_enabled));
1017                             break;
1018
1019                         case ProxyHelper.CUSTOM:
1020                             proxyPreference.setSummary(context.getString(R.string.custom_proxy));
1021                             break;
1022                     }
1023
1024                     // Update the status of the custom URL preference.
1025                     proxyCustomUrlPreference.setEnabled(currentProxyString.equals(ProxyHelper.CUSTOM));
1026
1027                     // Update the icons.
1028                     if (currentProxyString.equals(ProxyHelper.NONE)) {  // Proxying is disabled.
1029                         // Set the main proxy icon to be disabled
1030                         proxyPreference.setIcon(R.drawable.proxy_disabled);
1031
1032                         // Set the custom proxy URL icon to be ghosted.
1033                         proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
1034                     } else {  // Proxying is enabled.
1035                         // Set the main proxy icon to be enabled.
1036                         proxyPreference.setIcon(R.drawable.proxy_enabled);
1037
1038                         /// Set the custom proxy URL icon according to its status.
1039                         if (proxyCustomUrlPreference.isEnabled()) {
1040                             proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled);
1041                         } else {
1042                             proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted);
1043                         }
1044                     }
1045                     break;
1046
1047                 case "proxy_custom_url":
1048                     // Set the summary text for the proxy custom URL.
1049                     proxyCustomUrlPreference.setSummary(sharedPreferences.getString(context.getString(R.string.proxy_custom_url_key), context.getString(R.string.proxy_custom_url_default_value)));
1050                     break;
1051
1052                 case "full_screen_browsing_mode":
1053                     if (sharedPreferences.getBoolean("full_screen_browsing_mode", false)) {  // Full screen browsing is enabled.
1054                         // Set the full screen browsing mode preference icon.
1055                         fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
1056
1057                         // Set the hide app bar preference icon.
1058                         if (sharedPreferences.getBoolean("hide_app_bar", true)) {
1059                             hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1060                         } else {
1061                             hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1062                         }
1063                     } else {  // Full screen browsing is disabled.
1064                         // Update the icons.
1065                         fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
1066                         hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted);
1067                     }
1068                     break;
1069
1070                 case "hide_app_bar":
1071                     // Update the icon.
1072                     if (sharedPreferences.getBoolean("hide_app_bar", true)) {
1073                         hideAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1074                     } else {  // Hide app bar is disabled.
1075                         // Set the icon according to the theme.
1076                         hideAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1077                     }
1078                     break;
1079
1080                 case "clear_everything":
1081                     // Store the new clear everything status
1082                     boolean newClearEverythingBoolean = sharedPreferences.getBoolean("clear_everything", true);
1083
1084                     // Update the status of the clear and exit preferences.
1085                     clearCookiesPreference.setEnabled(!newClearEverythingBoolean);
1086                     clearDomStoragePreference.setEnabled(!newClearEverythingBoolean);
1087                     clearFormDataPreference.setEnabled(!newClearEverythingBoolean);  // This line can be removed once the minimum API >= 26.
1088                     clearLogcatPreference.setEnabled(!newClearEverythingBoolean);
1089                     clearCachePreference.setEnabled(!newClearEverythingBoolean);
1090
1091                     // Update the clear everything preference icon.
1092                     if (newClearEverythingBoolean) {
1093                         clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
1094                     } else {
1095                         clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
1096                     }
1097
1098                     // Update the clear cookies preference icon.
1099                     if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cookies", true)) {
1100                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
1101                     } else {
1102                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
1103                     }
1104
1105                     // Update the clear dom storage preference icon.
1106                     if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_dom_storage", true)) {
1107                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
1108                     } else {
1109                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
1110                     }
1111
1112                     // Update the clear form data preference icon if the API < 26.
1113                     if (Build.VERSION.SDK_INT < 26) {
1114                         if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_form_data", true)) {
1115                             clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
1116                         } else {
1117                             clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
1118                         }
1119                     }
1120
1121                     // Update the clear logcat preference icon.
1122                     if (newClearEverythingBoolean || sharedPreferences.getBoolean(context.getString(R.string.clear_logcat_key), true)) {
1123                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
1124                     } else {
1125                         clearLogcatPreference.setIcon(R.drawable.clear_cache_disabled);
1126                     }
1127
1128                     // Update the clear cache preference icon.
1129                     if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cache", true)) {
1130                         clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
1131                     } else {
1132                         clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
1133                     }
1134                     break;
1135
1136                 case "clear_cookies":
1137                     // Update the icon.
1138                     if (sharedPreferences.getBoolean("clear_cookies", true)) {
1139                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled);
1140                     } else {
1141                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled);
1142                     }
1143                     break;
1144
1145                 case "clear_dom_storage":
1146                     // Update the icon.
1147                     if (sharedPreferences.getBoolean("clear_dom_storage", true)) {
1148                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled);
1149                     } else {
1150                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled);
1151                     }
1152                     break;
1153
1154                 // This section can be removed once the minimum API >= 26.
1155                 case "clear_form_data":
1156                     // Update the icon.
1157                     if (sharedPreferences.getBoolean("clear_form_data", true)) {
1158                         clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled);
1159                     } else {
1160                         clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled);
1161                     }
1162                     break;
1163
1164                 case "clear_logcat":
1165                     // Update the icon.
1166                     if (sharedPreferences.getBoolean(context.getString(R.string.clear_logcat_key), true)) {
1167                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled);
1168                     } else {
1169                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled);
1170                     }
1171                     break;
1172
1173                 case "clear_cache":
1174                     // Update the icon.
1175                     if (sharedPreferences.getBoolean("clear_cache", true)) {
1176                         clearCachePreference.setIcon(R.drawable.clear_cache_enabled);
1177                     } else {
1178                         clearCachePreference.setIcon(R.drawable.clear_cache_disabled);
1179                     }
1180                     break;
1181
1182                 case "homepage":
1183                     // Set the new homepage URL as the summary text for the Homepage preference.
1184                     homepagePreference.setSummary(sharedPreferences.getString("homepage", context.getString(R.string.homepage_default_value)));
1185                     break;
1186
1187                 case "font_size":
1188                     // Update the font size summary text.
1189                     fontSizePreference.setSummary(sharedPreferences.getString("font_size", context.getString(R.string.font_size_default_value)) + "%");
1190                     break;
1191
1192                 case "open_intents_in_new_tab":
1193                     // Update the icon.
1194                     if (sharedPreferences.getBoolean("open_intents_in_new_tab", true)) {
1195                         openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled);
1196                     } else {
1197                         openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled);
1198                     }
1199                     break;
1200
1201                 case "swipe_to_refresh":
1202                     // Update the icon.
1203                     if (sharedPreferences.getBoolean("swipe_to_refresh", true)) {
1204                         swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
1205                     } else {
1206                         swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
1207                     }
1208                     break;
1209
1210                 case "download_with_external_app":
1211                     // Update the icon.
1212                     if (sharedPreferences.getBoolean(context.getString(R.string.download_with_external_app_key), false)) {
1213                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled);
1214                     } else {
1215                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled);
1216                     }
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)) scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled);
1222                     else scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled);
1223
1224                     break;
1225
1226                 case "bottom_app_bar":
1227                     // Update the icon.
1228                     if (sharedPreferences.getBoolean(context.getString(R.string.bottom_app_bar_key), false)) bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled);
1229                     else bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled);
1230
1231                     // Restart Privacy Browser.
1232                     restartPrivacyBrowser();
1233                     break;
1234
1235                 case "display_additional_app_bar_icons":
1236                     // Update the icon.
1237                     if (sharedPreferences.getBoolean(context.getString(R.string.display_additional_app_bar_icons_key), false)) {
1238                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
1239                     } else {
1240                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
1241                     }
1242                     break;
1243
1244                 case "app_theme":
1245                     // Get the new theme.
1246                     String newAppTheme = sharedPreferences.getString("app_theme", context.getString(R.string.app_theme_default_value));
1247
1248                     // 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.
1249                     if (newAppTheme.equals(appThemeEntryValuesStringArray[1])) {  // The light theme is selected.
1250                         // Update the theme preference summary text.
1251                         appThemePreference.setSummary(appThemeEntriesStringArray[1]);
1252
1253                         // Apply the new theme.
1254                         AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
1255                     } else if (newAppTheme.equals(appThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
1256                         // Update the theme preference summary text.
1257                         appThemePreference.setSummary(appThemeEntriesStringArray[2]);
1258
1259                         // Apply the new theme.
1260                         AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
1261                     } else {  // The system default theme is selected.
1262                         // Update the theme preference summary text.
1263                         appThemePreference.setSummary(appThemeEntriesStringArray[0]);
1264
1265                         // Apply the new theme.
1266                         if (Build.VERSION.SDK_INT >= 28) {  // The system default theme is supported.
1267                             // Follow the system default theme.
1268                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
1269                         } else {// The system default theme is not supported.
1270                             // Follow the battery saver mode.
1271                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
1272                         }
1273                     }
1274
1275                     // Update the current theme status.
1276                     currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
1277                     break;
1278
1279                 case "webview_theme":
1280                     // Get the new WebView theme.
1281                     String newWebViewTheme = sharedPreferences.getString("webview_theme", context.getString(R.string.webview_theme_default_value));
1282
1283                     // Define a new WebView theme entry number.
1284                     int newWebViewThemeEntryNumber;
1285
1286                     // 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.
1287                     if (newWebViewTheme.equals(webViewThemeEntriesStringArray[1])) {  // The light theme is selected.
1288                         // Store the new WebView theme entry number.
1289                         newWebViewThemeEntryNumber = 1;
1290                     } else if (newWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) {  // The dark theme is selected.
1291                         // Store the WebView theme entry number.
1292                         newWebViewThemeEntryNumber = 2;
1293                     } else {  // The system default theme is selected.
1294                         // Store the WebView theme entry number.
1295                         newWebViewThemeEntryNumber = 0;
1296                     }
1297
1298                     // Update the icon.
1299                     switch (newWebViewThemeEntryNumber) {
1300                         case 0:  // The system default WebView theme is selected.
1301                             // Set the icon.
1302                             if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1303                                 webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1304                             } else {
1305                                 webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1306                             }
1307                             break;
1308
1309                         case 1:  // The light theme is selected.
1310                             // Set the icon.
1311                             webViewThemePreference.setIcon(R.drawable.webview_light_theme);
1312                             break;
1313
1314                         case 2:  // The dark theme is selected.
1315                             // Set the icon.
1316                             webViewThemePreference.setIcon(R.drawable.webview_dark_theme);
1317                             break;
1318                     }
1319
1320                     // Set the current theme as the summary text for the preference.
1321                     webViewThemePreference.setSummary(webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]);
1322                     break;
1323
1324                 case "wide_viewport":
1325                     // Update the icon.
1326                     if (sharedPreferences.getBoolean("wide_viewport", true)) {
1327                         wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled);
1328                     } else {
1329                         wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled);
1330                     }
1331                     break;
1332
1333                 case "display_webpage_images":
1334                     // Update the icon.
1335                     if (sharedPreferences.getBoolean("display_webpage_images", true)) {
1336                         displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
1337                     } else {
1338                         displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
1339                     }
1340                     break;
1341             }
1342         };
1343     }
1344
1345     private void restartPrivacyBrowser() {
1346         // Create an intent to restart Privacy Browser.
1347         Intent restartIntent = requireActivity().getParentActivityIntent();
1348
1349         // Assert that the intent is not null to remove the lint error below.
1350         assert restartIntent != null;
1351
1352         // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack.  It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1353         restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1354
1355         // Create a handler to restart the activity.
1356         Handler restartHandler = new Handler(Looper.getMainLooper());
1357
1358         // Create a runnable to restart the activity.
1359         Runnable restartRunnable = () -> {
1360             // Restart the activity.
1361             startActivity(restartIntent);
1362
1363             // Kill this instance of Privacy Browser.  Otherwise, the app exhibits sporadic behavior after the restart.
1364             System.exit(0);
1365         };
1366
1367         // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1368         restartHandler.postDelayed(restartRunnable, 400);
1369     }
1370 }