]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java
Refactor style code to use attrs.xml. Create a dark theme for Find on Page.
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / fragments / SettingsFragment.java
1 /*
2  * Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
6  * Privacy Browser 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 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.  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.content.Intent;
24 import android.content.SharedPreferences;
25 import android.os.Build;
26 import android.os.Bundle;
27 import android.preference.Preference;
28 import android.preference.PreferenceFragment;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.webkit.WebView;
32
33 import com.stoutner.privacybrowser.R;
34 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
35
36 public class SettingsFragment extends PreferenceFragment {
37     private SharedPreferences.OnSharedPreferenceChangeListener preferencesListener;
38     private SharedPreferences savedPreferences;
39
40     @Override
41     public void onCreate(Bundle savedInstanceState) {
42         super.onCreate(savedInstanceState);
43         addPreferencesFromResource(R.xml.preferences);
44
45         // Initialize savedPreferences.
46         savedPreferences = getPreferenceScreen().getSharedPreferences();
47
48         // Get handles for the preferences we need to modify.
49         final Preference javaScriptPreference = findPreference("javascript_enabled");
50         final Preference firstPartyCookiesPreference = findPreference("first_party_cookies_enabled");
51         final Preference thirdPartyCookiesPreference = findPreference("third_party_cookies_enabled");
52         final Preference domStoragePreference = findPreference("dom_storage_enabled");
53         final Preference saveFormDataPreference = findPreference("save_form_data_enabled");
54         final Preference userAgentPreference = findPreference("user_agent");
55         final Preference customUserAgentPreference = findPreference("custom_user_agent");
56         final Preference blockAdsPreference = findPreference("block_ads");
57         final Preference incognitoModePreference = findPreference("incognito_mode");
58         final Preference doNotTrackPreference = findPreference("do_not_track");
59         final Preference proxyThroughOrbotPreference = findPreference("proxy_through_orbot");
60         final Preference torHomepagePreference = findPreference("tor_homepage");
61         final Preference torSearchPreference = findPreference("tor_search");
62         final Preference torSearchCustomURLPreference = findPreference("tor_search_custom_url");
63         final Preference searchPreference = findPreference("search");
64         final Preference searchCustomURLPreference = findPreference("search_custom_url");
65         final Preference fullScreenBrowsingModePreference = findPreference("full_screen_browsing_mode");
66         final Preference hideSystemBarsPreference = findPreference("hide_system_bars");
67         final Preference translucentNavigationBarPreference = findPreference("translucent_navigation_bar");
68         final Preference clearEverythingPreference = findPreference("clear_everything");
69         final Preference clearCookiesPreference = findPreference("clear_cookies");
70         final Preference clearDomStoragePreference = findPreference("clear_dom_storage");
71         final Preference clearFormDataPreference = findPreference("clear_form_data");
72         final Preference clearCachePreference = findPreference("clear_cache");
73         final Preference homepagePreference = findPreference("homepage");
74         final Preference defaultFontSizePreference = findPreference("default_font_size");
75         final Preference swipeToRefreshPreference = findPreference("swipe_to_refresh");
76         final Preference displayAdditionalAppBarIconsPreference = findPreference("display_additional_app_bar_icons");
77         final Preference darkThemePreference = findPreference("dark_theme");
78         final Preference displayWebpageImagesPreference = findPreference("display_webpage_images");
79
80         // Set dependencies.
81         domStoragePreference.setDependency("javascript_enabled");
82         torHomepagePreference.setDependency("proxy_through_orbot");
83         torSearchPreference.setDependency("proxy_through_orbot");
84         hideSystemBarsPreference.setDependency("full_screen_browsing_mode");
85
86         // Get strings from the preferences.
87         String torSearchString = savedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
88         String searchString = savedPreferences.getString("search", "https://duckduckgo.com/html/?q=");
89
90         // Get booleans from the preferences.
91         boolean javaScriptEnabledBoolean = savedPreferences.getBoolean("javascript_enabled", false);
92         boolean firstPartyCookiesEnabledBoolean = savedPreferences.getBoolean("first_party_cookies_enabled", false);
93         boolean thirdPartyCookiesEnabledBoolean = savedPreferences.getBoolean("third_party_cookies_enabled", false);
94         boolean proxyThroughOrbotBoolean = savedPreferences.getBoolean("proxy_through_orbot", false);
95         boolean fullScreenBrowsingModeBoolean = savedPreferences.getBoolean("full_screen_browsing_mode", false);
96         boolean hideSystemBarsBoolean = savedPreferences.getBoolean("hide_system_bars", false);
97         boolean clearEverythingBoolean = savedPreferences.getBoolean("clear_everything", true);
98
99         // Only enable `thirdPartyCookiesPreference` if `firstPartyCookiesEnabledBoolean` is `true` and API >= 21.
100         thirdPartyCookiesPreference.setEnabled(firstPartyCookiesEnabledBoolean && (Build.VERSION.SDK_INT >= 21));
101
102         // We need to inflated a `WebView` to get the default user agent.
103         LayoutInflater inflater = getActivity().getLayoutInflater();
104         // `@SuppressLint("InflateParams")` removes the warning about using `null` as the `ViewGroup`, which in this case makes sense because we don't want to display `bare_webview` on the screen.  `false` does not attach the view to the root.
105         @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
106         final WebView bareWebView = (WebView) bareWebViewLayout.findViewById(R.id.bare_webview);
107
108         // Set the current user-agent as the summary text for the "user_agent" preference when the preference screen is loaded.
109         switch (savedPreferences.getString("user_agent", "PrivacyBrowser/1.0")) {
110             case "WebView default user agent":
111                 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
112                 userAgentPreference.setSummary(bareWebView.getSettings().getUserAgentString());
113                 break;
114
115             case "Custom user agent":
116                 // We can't use the string from the array because it is referenced in code and can't be translated.
117                 userAgentPreference.setSummary(R.string.custom_user_agent);
118                 break;
119
120             default:
121                 // Display the user agent from the preference as the summary text.
122                 userAgentPreference.setSummary(savedPreferences.getString("user_agent", "PrivacyBrowser/1.0"));
123                 break;
124         }
125
126         // Set the summary text for "customUserAgentPreference" (the default is `PrivacyBrowser/1.0`) and enable it if `userAgentPreference` it set to `Custom user agent`.
127         customUserAgentPreference.setSummary(savedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0"));
128         customUserAgentPreference.setEnabled(userAgentPreference.getSummary().equals("Custom user agent"));
129
130
131         // Set the Tor homepage URL as the summary text for the `tor_homepage` preference when the preference screen is loaded.  The default is DuckDuckGo: `https://3g2upl4pq6kufc4m.onion`.
132         torHomepagePreference.setSummary(savedPreferences.getString("tor_homepage", "https://3g2upl4pq6kufc4m.onion"));
133
134
135         // Set the Tor search URL as the summary text for the Tor preference when the preference screen is loaded.  The default is `https://3g2upl4pq6kufc4m.onion/html/?q=`
136         if (torSearchString.equals("Custom URL")) {
137             // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
138             torSearchPreference.setSummary(R.string.custom_url);
139         } else {
140             // Set the array value as the summary text.
141             torSearchPreference.setSummary(torSearchString);
142         }
143
144         // Set the summary text for `tor_search_custom_url`.  The default is `""`.
145         torSearchCustomURLPreference.setSummary(savedPreferences.getString("tor_search_custom_url", ""));
146
147         // Enable the Tor custom URL search options only if proxying through Orbot and the search is set to `Custom URL`.
148         torSearchCustomURLPreference.setEnabled(proxyThroughOrbotBoolean && torSearchString.equals("Custom URL"));
149
150
151         // Set the search URL as the summary text for the search preference when the preference screen is loaded.  The default is `https://duckduckgo.com/html/?q=`.
152         if (searchString.equals("Custom URL")) {
153             // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
154             searchPreference.setSummary(R.string.custom_url);
155         } else {
156             // Set the array value as the summary text.
157             searchPreference.setSummary(searchString);
158         }
159
160         // Set the summary text for `search_custom_url` (the default is `""`) and enable it if `search` is set to `Custom URL`.
161         searchCustomURLPreference.setSummary(savedPreferences.getString("search_custom_url", ""));
162         searchCustomURLPreference.setEnabled(searchString.equals("Custom URL"));
163
164
165         // Enable `translucentNavigationBarPreference` only if full screen browsing mode is enabled and `hide_system_bars` is disabled.
166         translucentNavigationBarPreference.setEnabled(fullScreenBrowsingModeBoolean && !hideSystemBarsBoolean);
167
168         // Set the status of the `Clear and Exit` preferences.
169         clearCookiesPreference.setEnabled(!clearEverythingBoolean);
170         clearDomStoragePreference.setEnabled(!clearEverythingBoolean);
171         clearFormDataPreference.setEnabled(!clearEverythingBoolean);
172         clearCachePreference.setEnabled(!clearEverythingBoolean);
173
174         // Set the homepage URL as the summary text for the `Homepage` preference when the preference screen is loaded.  The default is `https://duckduckgo.com`.
175         homepagePreference.setSummary(savedPreferences.getString("homepage", "https://duckduckgo.com"));
176
177         // Set the default font size as the summary text for the `Default Font Size` preference when the preference screen is loaded.  The default is `100`.
178         defaultFontSizePreference.setSummary(savedPreferences.getString("default_font_size", "100") + "%%");
179
180
181         // Set the `javaScriptPreference` icon.
182         if (javaScriptEnabledBoolean) {
183             javaScriptPreference.setIcon(R.drawable.javascript_enabled);
184         } else {
185             javaScriptPreference.setIcon(R.drawable.privacy_mode);
186         }
187
188         // Set the `firstPartyCookiesPreference` icon.
189         if (firstPartyCookiesEnabledBoolean) {
190             firstPartyCookiesPreference.setIcon(R.drawable.cookies_enabled);
191         } else {
192             firstPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
193         }
194
195         // Set the `thirdPartyCookiesPreference` icon.
196         if (firstPartyCookiesEnabledBoolean && Build.VERSION.SDK_INT >= 21) {
197             if (thirdPartyCookiesEnabledBoolean) {
198                 thirdPartyCookiesPreference.setIcon(R.drawable.cookies_warning);
199             } else {
200                 thirdPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
201             }
202         } else {
203             thirdPartyCookiesPreference.setIcon(R.drawable.cookies_ghosted);
204         }
205
206         // Set the `domStoragePreference` icon.
207         if (javaScriptEnabledBoolean) {
208             if (savedPreferences.getBoolean("dom_storage_enabled", false)) {
209                 domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
210             } else {
211                 domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
212             }
213         } else {
214             domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
215         }
216
217         // Set the `saveFormDataPreference` icon.
218         if (savedPreferences.getBoolean("save_form_data_enabled", false)) {
219             saveFormDataPreference.setIcon(R.drawable.form_data_enabled);
220         } else {
221             saveFormDataPreference.setIcon(R.drawable.form_data_disabled);
222         }
223
224         // Set the `customUserAgentPreference` icon.
225         if (customUserAgentPreference.isEnabled()) {
226             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
227         } else {
228             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
229         }
230
231         // Set the `blockAdsPreference` icon.
232         if (savedPreferences.getBoolean("block_ads", true)) {
233             blockAdsPreference.setIcon(R.drawable.block_ads_enabled);
234         } else {
235             blockAdsPreference.setIcon(R.drawable.block_ads_disabled);
236         }
237
238         // Set the `incognitoModePreference` icon.
239         if (savedPreferences.getBoolean("incognito_mode", false)) {
240             incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
241         } else {
242             incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
243         }
244
245         // Set the `doNotTrackPreference` icon.
246         if (savedPreferences.getBoolean("do_not_track", false)) {
247             doNotTrackPreference.setIcon(R.drawable.do_not_track_enabled);
248         } else {
249             doNotTrackPreference.setIcon(R.drawable.do_not_track_disabled);
250         }
251
252         // Set the `proxyThroughOrbotPreference` icon.
253         if (proxyThroughOrbotBoolean) {
254             proxyThroughOrbotPreference.setIcon(R.drawable.orbot_enabled);
255         } else {
256             proxyThroughOrbotPreference.setIcon(R.drawable.orbot_disabled);
257         }
258
259         // Set the `torSearchPreference` and `torSearchCustomURLPreference` icons.
260         if (proxyThroughOrbotBoolean) {
261             // Set the `torHomepagePreference` and `torSearchPreference` icons.
262             torHomepagePreference.setIcon(R.drawable.home_enabled);
263             torSearchPreference.setIcon(R.drawable.search_enabled);
264
265             // Set the `torSearchCustomURLPreference` icon.
266             if (torSearchCustomURLPreference.isEnabled()) {
267                 torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
268             } else {
269                 torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_disabled);
270             }
271         } else {  // Proxy through Orbot is disabled.
272             torHomepagePreference.setIcon(R.drawable.home_ghosted);
273             torSearchPreference.setIcon(R.drawable.search_ghosted);
274             torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_ghosted);
275         }
276
277         // Set the `searchCustomURLPreference` icon.
278         if (searchCustomURLPreference.isEnabled()) {
279             searchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
280         } else {
281             searchCustomURLPreference.setIcon(R.drawable.search_custom_url_ghosted);
282         }
283
284         // Set the full screen browsing mode icons.
285         if (fullScreenBrowsingModeBoolean) {
286             // Set the `fullScreenBrowsingModePreference` icon.
287             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
288
289             if (hideSystemBarsBoolean) {
290                 // Set `hideSystemBarsPreference` to use the enabled icon.
291                 hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_enabled);
292
293                 // Set `translucentNavigationBarPreference` to use the ghosted icon.
294                 translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
295             } else {  // `hideSystemBarsBoolean` is false.
296                 // Set `hideSystemBarsPreference` to use the disabled icon.
297                 hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_disabled);
298
299                 // Set the correct icon for `translucentNavigationBarPreference`.
300                 if (savedPreferences.getBoolean("translucent_navigation_bar", true)) {
301                     translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_enabled);
302                 } else {
303                     translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_disabled);
304                 }
305             }
306         } else {  // `fullScreenBrowsingModeBoolean` is false.
307             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
308             hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_ghosted);
309             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
310         }
311
312         // Set the `clearEverythingPreference` icon.
313         if (clearEverythingBoolean) {
314             clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
315         } else {
316             clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
317         }
318
319         // Set the `clearCookiesPreference` icon.
320         if (clearEverythingBoolean || savedPreferences.getBoolean("clear_cookies", true)) {
321             clearCookiesPreference.setIcon(R.drawable.cookies_cleared);
322         } else {
323             clearCookiesPreference.setIcon(R.drawable.cookies_warning);
324         }
325
326         // Set the `clearDomStoragePreference` icon.
327         if (clearEverythingBoolean || savedPreferences.getBoolean("clear_dom_storage", true)) {
328             clearDomStoragePreference.setIcon(R.drawable.dom_storage_cleared);
329         } else {
330             clearDomStoragePreference.setIcon(R.drawable.dom_storage_warning);
331         }
332
333         // Set the `clearFormDataPreference` icon.
334         if (clearEverythingBoolean || savedPreferences.getBoolean("clear_form_data", true)) {
335             clearFormDataPreference.setIcon(R.drawable.form_data_cleared);
336         } else {
337             clearFormDataPreference.setIcon(R.drawable.form_data_warning);
338         }
339
340         // Set the `clearCachePreference` icon.
341         if (clearEverythingBoolean || savedPreferences.getBoolean("clear_cache", true)) {
342             clearCachePreference.setIcon(R.drawable.cache_cleared);
343         } else {
344             clearCachePreference.setIcon(R.drawable.cache_warning);
345         }
346
347         // Set the `swipeToRefreshPreference` icon.
348         if (savedPreferences.getBoolean("swipe_to_refresh", false)) {
349             swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
350         } else {
351             swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
352         }
353
354         // Set the `displayAdditionalAppBarIconsPreference` icon.
355         if (savedPreferences.getBoolean("display_additional_app_bar_icons", false)) {
356             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
357         } else {
358             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
359         }
360
361         // Set the `darkThemePreference` icon.
362         if (savedPreferences.getBoolean("dark_theme", false)) {
363             darkThemePreference.setIcon(R.drawable.theme_dark);
364         } else {
365             darkThemePreference.setIcon(R.drawable.theme_light);
366         }
367
368         // Set the `displayWebpageImagesPreference` icon.
369         if (savedPreferences.getBoolean("display_webpage_images", true)) {
370             displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
371         } else {
372             displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
373         }
374
375
376         // Listen for preference changes.
377         preferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
378             @Override
379             // Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled.  We know.
380             @SuppressLint("SetJavaScriptEnabled")
381             public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
382
383                 switch (key) {
384                     case "javascript_enabled":
385                         // Update the icons.
386                         if (sharedPreferences.getBoolean("javascript_enabled", false)) {
387                             // Update the icon for `javascript_enabled`.
388                             javaScriptPreference.setIcon(R.drawable.javascript_enabled);
389
390                             // Update the icon for `dom_storage_enabled`.
391                             if (sharedPreferences.getBoolean("dom_storage_enabled", false)) {
392                                 domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
393                             } else {
394                                 domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
395                             }
396                         } else {  // `javascript_enabled` is `false`.
397                             // Update the icon for `javascript_enabled`.
398                             javaScriptPreference.setIcon(R.drawable.privacy_mode);
399
400                             // Set the icon for `dom_storage_disabled` to be ghosted.
401                             domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
402                         }
403                         break;
404
405                     case "first_party_cookies_enabled":
406                         // Update the icons for `first_party_cookies_enabled` and `third_party_cookies_enabled`.
407                         if (sharedPreferences.getBoolean("first_party_cookies_enabled", false)) {
408                             // Set the icon for `first_party_cookies_enabled`.
409                             firstPartyCookiesPreference.setIcon(R.drawable.cookies_enabled);
410
411                             // Update the icon for `third_party_cookies_enabled`.
412                             if (Build.VERSION.SDK_INT >= 21) {
413                                 if (sharedPreferences.getBoolean("third_party_cookies_enabled", false)) {
414                                     thirdPartyCookiesPreference.setIcon(R.drawable.cookies_warning);
415                                 } else {
416                                     thirdPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
417                                 }
418                             } else {
419                                 thirdPartyCookiesPreference.setIcon(R.drawable.cookies_ghosted);
420                             }
421                         } else {  // `first_party_cookies_enabled` is `false`.
422                             // Update the icon for `first_party_cookies_enabled`.
423                             firstPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
424
425                             // Set the icon for `third_party_cookies_enabled` to be ghosted.
426                             thirdPartyCookiesPreference.setIcon(R.drawable.cookies_ghosted);
427                         }
428
429                         // Enable `third_party_cookies_enabled` if `first_party_cookies_enabled` is `true` and API >= 21.
430                         thirdPartyCookiesPreference.setEnabled(sharedPreferences.getBoolean("first_party_cookies_enabled", false) && (Build.VERSION.SDK_INT >= 21));
431                         break;
432
433                     case "third_party_cookies_enabled":
434                         // Update the icon.
435                         if (sharedPreferences.getBoolean("third_party_cookies_enabled", false)) {
436                             thirdPartyCookiesPreference.setIcon(R.drawable.cookies_warning);
437                         } else {
438                             thirdPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
439                         }
440                         break;
441
442                     case "dom_storage_enabled":
443                         // Update the icon.
444                         if (sharedPreferences.getBoolean("dom_storage_enabled", false)) {
445                             domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
446                         } else {
447                             domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
448                         }
449                         break;
450
451                     case "save_form_data_enabled":
452                         // Update the icon.
453                         if (sharedPreferences.getBoolean("save_form_data_enabled", false)) {
454                             saveFormDataPreference.setIcon(R.drawable.form_data_enabled);
455                         } else {
456                             saveFormDataPreference.setIcon(R.drawable.form_data_disabled);
457                         }
458
459                     case "user_agent":
460                         String userAgentString = sharedPreferences.getString("user_agent", "PrivacyBrowser/1.0");
461
462                         switch (userAgentString) {
463                             case "WebView default user agent":
464                                 // Display the user agent as the summary text for `userAgentPreference`.
465                                 userAgentPreference.setSummary(bareWebView.getSettings().getUserAgentString());
466
467                                 // Update `customUserAgentPreference`.
468                                 customUserAgentPreference.setEnabled(false);
469                                 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
470                                 break;
471
472                             case "Custom user agent":
473                                 // Display `Custom user agent` as the summary text for `userAgentPreference`.
474                                 userAgentPreference.setSummary(R.string.custom_user_agent);
475
476                                 // Update `customUserAgentPreference`.
477                                 customUserAgentPreference.setEnabled(true);
478                                 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
479                                 break;
480
481                             default:
482                                 // Display the user agent as the summary text for `userAgentPreference`.
483                                 userAgentPreference.setSummary(sharedPreferences.getString("user_agent", "PrivacyBrowser/1.0"));
484
485                                 // Update `customUserAgentPreference`.
486                                 customUserAgentPreference.setEnabled(false);
487                                 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
488                                 break;
489                         }
490                         break;
491
492                     case "custom_user_agent":
493                         // Set the new custom user agent as the summary text for `custom_user_agent`.  The default is `PrivacyBrowser/1.0`.
494                         customUserAgentPreference.setSummary(sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0"));
495                         break;
496
497                     case "block_ads":
498                         // Update the icon.
499                         if (sharedPreferences.getBoolean("block_ads", true)) {
500                             blockAdsPreference.setIcon(R.drawable.block_ads_enabled);
501                         } else {
502                             blockAdsPreference.setIcon(R.drawable.block_ads_disabled);
503                         }
504                         break;
505
506                     case "incognito_mode":
507                         // Update the icon.
508                         if (sharedPreferences.getBoolean("incognito_mode", false)) {
509                             incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
510                         } else {
511                             incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
512                         }
513                         break;
514
515                     case "do_not_track":
516                         // Update the icon.
517                         if (sharedPreferences.getBoolean("do_not_track", false)) {
518                             doNotTrackPreference.setIcon(R.drawable.do_not_track_enabled);
519                         } else {
520                             doNotTrackPreference.setIcon(R.drawable.do_not_track_disabled);
521                         }
522
523                         break;
524
525                     case "proxy_through_orbot":
526                         // Get current settings.
527                         boolean currentProxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
528                         String currentTorSearchString = sharedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
529
530                         // Enable the Tor custom URL search option only if `currentProxyThroughOrbot` is true and the search is set to `Custom URL`.
531                         torSearchCustomURLPreference.setEnabled(currentProxyThroughOrbot && currentTorSearchString.equals("Custom URL"));
532
533                         // Update the icons.
534                         if (currentProxyThroughOrbot) {
535                             // Set the `proxyThroughOrbotPreference`, `torHomepagePreference`, and `torSearchPreference` icons.
536                             proxyThroughOrbotPreference.setIcon(R.drawable.orbot_enabled);
537                             torHomepagePreference.setIcon(R.drawable.home_enabled);
538                             torSearchPreference.setIcon(R.drawable.search_enabled);
539
540                             // Set the `torSearchCustomURLPreference` icon.
541                             if (torSearchCustomURLPreference.isEnabled()) {
542                                 torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
543                             } else {
544                                 torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_disabled);
545                             }
546                         } else {  // Proxy through Orbot is disabled.
547                             proxyThroughOrbotPreference.setIcon(R.drawable.orbot_disabled);
548                             torHomepagePreference.setIcon(R.drawable.home_ghosted);
549                             torSearchPreference.setIcon(R.drawable.search_ghosted);
550                             torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_ghosted);
551                         }
552                         break;
553
554                     case "tor_homepage":
555                         // Set the new tor homepage URL as the summary text for the `tor_homepage` preference.  The default is DuckDuckGo:  `https://3g2upl4pq6kufc4m.onion`.
556                         torHomepagePreference.setSummary(sharedPreferences.getString("tor_homepage", "https://3g2upl4pq6kufc4m.onion"));
557                         break;
558
559                     case "tor_search":
560                         // Get the present search string.
561                         String presentTorSearchString = sharedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
562
563                         // Update the preferences.
564                         if (presentTorSearchString.equals("Custom URL")) {
565                             // Use `R.string.custom_url`, which is translated, as the summary instead of the array value, which isn't.
566                             torSearchPreference.setSummary(R.string.custom_url);
567
568                             // Update `torSearchCustomURLPreference`.
569                             torSearchCustomURLPreference.setEnabled(true);
570                             torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
571                         } else {
572                             // Set the array value as the summary text.
573                             torSearchPreference.setSummary(presentTorSearchString);
574
575                             // Update `torSearchCustomURLPreference`.
576                             torSearchCustomURLPreference.setEnabled(false);
577                             torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_disabled);
578                         }
579                         break;
580
581                     case "tor_search_custom_url":
582                         // Set the summary text for `tor_search_custom_url`.
583                         torSearchCustomURLPreference.setSummary(sharedPreferences.getString("tor_search_custom_url", ""));
584                         break;
585
586                     case "search":
587                         // Store the new search string.
588                         String newSearchString = sharedPreferences.getString("search", "https://duckduckgo.com/html/?q=");
589
590                         // Update `searchPreference` and `searchCustomURLPreference`.
591                         if (newSearchString.equals("Custom URL")) {  // `Custom URL` is selected.
592                             // Set the summary text to `R.string.custom_url`, which is translated.
593                             searchPreference.setSummary(R.string.custom_url);
594
595                             // Update `searchCustomURLPreference`.
596                             searchCustomURLPreference.setEnabled(true);
597                             searchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
598                         } else {  // `Custom URL` is not selected.
599                             // Set the summary text to `newSearchString`.
600                             searchPreference.setSummary(newSearchString);
601
602                             // Update `searchCustomURLPreference`.
603                             searchCustomURLPreference.setEnabled(false);
604                             searchCustomURLPreference.setIcon(R.drawable.search_custom_url_ghosted);
605                         }
606                         break;
607
608                     case "search_custom_url":
609                         // Set the new custom search URL as the summary text for `search_custom_url`.  The default is `""`.
610                         searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", ""));
611                         break;
612
613                     case "full_screen_browsing_mode":
614                         if (sharedPreferences.getBoolean("full_screen_browsing_mode", false)) {
615                             // Set `fullScreenBrowsingModePreference` to use the enabled icon.
616                             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
617
618                             if (sharedPreferences.getBoolean("hide_system_bars", false)) {
619                                 // Set `hideSystemBarsPreference` to use the enabled icon.
620                                 hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_enabled);
621
622                                 // Update `translucentNavigationBarPreference`.
623                                 translucentNavigationBarPreference.setEnabled(false);
624                                 translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
625                             } else {  // `hide_system_bars` is false.
626                                 // Set `hideSystemBarsPreference` to use the disabled icon.
627                                 hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_disabled);
628
629                                 // Update `translucentNavigationBarPreference`.
630                                 translucentNavigationBarPreference.setEnabled(true);
631                                 if (sharedPreferences.getBoolean("translucent_navigation_bar", true)) {
632                                     translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_enabled);
633                                 } else {
634                                     translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_disabled);
635                                 }
636                             }
637                         } else {  // `full_screen_browsing_mode` is false.
638                             // Disable `translucentNavigationBarPreference`.
639                             translucentNavigationBarPreference.setEnabled(false);
640
641                             // Update the icons.
642                             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
643                             hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_ghosted);
644                             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
645                         }
646                         break;
647
648                     case "hide_system_bars":
649                         if (sharedPreferences.getBoolean("hide_system_bars", false)) {
650                             // Set `hideSystemBarsPreference` to use the enabled icon.
651                             hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_enabled);
652
653                             // Update `translucentNavigationBarPreference`.
654                             translucentNavigationBarPreference.setEnabled(false);
655                             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
656                         } else {  // `hide_system_bars` is false.
657                             // Set `hideSystemBarsPreference` to use the disabled icon.
658                             hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_disabled);
659
660                             // Update `translucentNavigationBarPreference`.
661                             translucentNavigationBarPreference.setEnabled(true);
662                             if (sharedPreferences.getBoolean("translucent_navigation_bar", true)) {
663                                 translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_enabled);
664                             } else {
665                                 translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_disabled);
666                             }
667                         }
668                         break;
669
670                     case "translucent_navigation_bar":
671                         // Update the icon.
672                         if (sharedPreferences.getBoolean("translucent_navigation_bar", true)) {
673                             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_enabled);
674                         } else {
675                             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_disabled);
676                         }
677                         break;
678
679                     case "clear_everything":
680                         // Store the new `clear_everything` status
681                         boolean newClearEverythingBoolean = sharedPreferences.getBoolean("clear_everything", true);
682
683                         // Update the status of the `Clear and Exit` preferences.
684                         clearCookiesPreference.setEnabled(!newClearEverythingBoolean);
685                         clearDomStoragePreference.setEnabled(!newClearEverythingBoolean);
686                         clearFormDataPreference.setEnabled(!newClearEverythingBoolean);
687                         clearCachePreference.setEnabled(!newClearEverythingBoolean);
688
689                         // Update the `clearEverythingPreference` icon.
690                         if (newClearEverythingBoolean) {
691                             clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled);
692                         } else {
693                             clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled);
694                         }
695
696                         // Update the `clearCookiesPreference` icon.
697                         if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cookies", true)) {
698                             clearCookiesPreference.setIcon(R.drawable.cookies_cleared);
699                         } else {
700                             clearCookiesPreference.setIcon(R.drawable.cookies_warning);
701                         }
702
703                         // Update the `clearDomStoragePreference` icon.
704                         if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_dom_storage", true)) {
705                             clearDomStoragePreference.setIcon(R.drawable.dom_storage_cleared);
706                         } else {
707                             clearDomStoragePreference.setIcon(R.drawable.dom_storage_warning);
708                         }
709
710                         // Update the `clearFormDataPreference` icon.
711                         if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_form_data", true)) {
712                             clearFormDataPreference.setIcon(R.drawable.form_data_cleared);
713                         } else {
714                             clearFormDataPreference.setIcon(R.drawable.form_data_warning);
715                         }
716
717                         // Update the `clearCachePreference` icon.
718                         if (newClearEverythingBoolean || sharedPreferences.getBoolean("clear_cache", true)) {
719                             clearCachePreference.setIcon(R.drawable.cache_cleared);
720                         } else {
721                             clearCachePreference.setIcon(R.drawable.cache_warning);
722                         }
723                         break;
724
725                     case "clear_cookies":
726                         // Update the icon.
727                         if (sharedPreferences.getBoolean("clear_cookies", true)) {
728                             clearCookiesPreference.setIcon(R.drawable.cookies_cleared);
729                         } else {
730                             clearCookiesPreference.setIcon(R.drawable.cookies_warning);
731                         }
732                         break;
733
734                     case "clear_dom_storage":
735                         // Update the icon.
736                         if (sharedPreferences.getBoolean("clear_dom_storage", true)) {
737                             clearDomStoragePreference.setIcon(R.drawable.dom_storage_cleared);
738                         } else {
739                             clearDomStoragePreference.setIcon(R.drawable.dom_storage_warning);
740                         }
741                         break;
742
743                     case "clear_form_data":
744                         // Update the icon.
745                         if (sharedPreferences.getBoolean("clear_form_data", true)) {
746                             clearFormDataPreference.setIcon(R.drawable.form_data_cleared);
747                         } else {
748                             clearFormDataPreference.setIcon(R.drawable.form_data_warning);
749                         }
750                         break;
751
752                     case "clear_cache":
753                         // Update the icon.
754                         if (sharedPreferences.getBoolean("clear_cache", true)) {
755                             clearCachePreference.setIcon(R.drawable.cache_cleared);
756                         } else {
757                             clearCachePreference.setIcon(R.drawable.cache_warning);
758                         }
759                         break;
760
761                     case "homepage":
762                         // Set the new homepage URL as the summary text for the Homepage preference.  The default is `https://www.duckduckgo.com`.
763                         homepagePreference.setSummary(sharedPreferences.getString("homepage", "https://www.duckduckgo.com"));
764                         break;
765
766                     case "default_font_size":
767                         // Update the summary text of `default_font_size`.
768                         defaultFontSizePreference.setSummary(sharedPreferences.getString("default_font_size", "100") + "%%");
769                         break;
770
771                     case "swipe_to_refresh":
772                         // Update the icon.
773                         if (sharedPreferences.getBoolean("swipe_to_refresh", false)) {
774                             swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
775                         } else {
776                             swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
777                         }
778                         break;
779
780                     case "display_additional_app_bar_icons":
781                         // Update the icon.
782                         if (sharedPreferences.getBoolean("display_additional_app_bar_icons", false)) {
783                             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
784                         } else {
785                             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
786                         }
787                         break;
788
789                     case "dark_theme":
790                         // Update the icon.
791                         if (sharedPreferences.getBoolean("dark_theme", false)) {
792                             darkThemePreference.setIcon(R.drawable.theme_dark);
793                         } else {
794                             darkThemePreference.setIcon(R.drawable.theme_light);
795                         }
796
797                         // Create an `Intent` to restart Privacy Browser.
798                         Intent intent = getActivity().getParentActivityIntent();
799
800                         // Assert that `intent` is not `null` to remove the lint error below.
801                         assert intent != null;
802
803                         // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack.  It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
804                         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
805
806                         // Make it so.
807                         startActivity(intent);
808                         break;
809
810                     case "display_webpage_images":
811                         if (sharedPreferences.getBoolean("display_webpage_images", true)) {
812                             // Update the icon.
813                             displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
814
815                             // `mainWebView` does not need to be reloaded because unloaded images will load automatically.
816                             MainWebViewActivity.reloadOnRestartBoolean = false;
817                         } else {
818                             // Update the icon.
819                             displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
820
821                             // Set `mainWebView` to reload on restart to remove the current images.
822                             MainWebViewActivity.reloadOnRestartBoolean = true;
823                         }
824                         break;
825                 }
826             }
827         };
828
829         // Register the listener.
830         savedPreferences.registerOnSharedPreferenceChangeListener(preferencesListener);
831     }
832
833     // It is necessary to re-register the listener on every resume or it will randomly stop working because apps can be paused and resumed at any time
834     // even while running in the foreground.
835     @Override
836     public void onPause() {
837         super.onPause();
838         savedPreferences.unregisterOnSharedPreferenceChangeListener(preferencesListener);
839     }
840
841     @Override
842     public void onResume() {
843         super.onResume();
844         savedPreferences.registerOnSharedPreferenceChangeListener(preferencesListener);
845     }
846 }