Add controls for displaying webpage images. Implements https://redmine.stoutner...
[PrivacyBrowser.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.SharedPreferences;
24 import android.os.Build;
25 import android.os.Bundle;
26 import android.preference.Preference;
27 import android.preference.PreferenceFragment;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 import android.webkit.WebView;
31
32 import com.stoutner.privacybrowser.R;
33
34 public class SettingsFragment extends PreferenceFragment {
35     private SharedPreferences.OnSharedPreferenceChangeListener preferencesListener;
36     private SharedPreferences savedPreferences;
37
38     @Override
39     public void onCreate(Bundle savedInstanceState) {
40         super.onCreate(savedInstanceState);
41         addPreferencesFromResource(R.xml.preferences);
42
43         // Initialize savedPreferences.
44         savedPreferences = getPreferenceScreen().getSharedPreferences();
45
46         // Get handles for the preferences we need to modify.
47         final Preference javaScriptPreference = findPreference("javascript_enabled");
48         final Preference firstPartyCookiesPreference = findPreference("first_party_cookies_enabled");
49         final Preference thirdPartyCookiesPreference = findPreference("third_party_cookies_enabled");
50         final Preference domStoragePreference = findPreference("dom_storage_enabled");
51         final Preference saveFormDataPreference = findPreference("save_form_data_enabled");
52         final Preference userAgentPreference = findPreference("user_agent");
53         final Preference customUserAgentPreference = findPreference("custom_user_agent");
54         final Preference blockAdsPreference = findPreference("block_ads");
55         final Preference incognitoModePreference = findPreference("incognito_mode");
56         final Preference doNotTrackPreference = findPreference("do_not_track");
57         final Preference proxyThroughOrbotPreference = findPreference("proxy_through_orbot");
58         final Preference torHomepagePreference = findPreference("tor_homepage");
59         final Preference torSearchPreference = findPreference("tor_search");
60         final Preference torSearchCustomURLPreference = findPreference("tor_search_custom_url");
61         final Preference searchPreference = findPreference("search");
62         final Preference searchCustomURLPreference = findPreference("search_custom_url");
63         final Preference fullScreenBrowsingModePreference = findPreference("full_screen_browsing_mode");
64         final Preference hideSystemBarsPreference = findPreference("hide_system_bars");
65         final Preference translucentNavigationBarPreference = findPreference("translucent_navigation_bar");
66         final Preference homepagePreference = findPreference("homepage");
67         final Preference defaultFontSizePreference = findPreference("default_font_size");
68         final Preference swipeToRefreshPreference = findPreference("swipe_to_refresh");
69         final Preference displayAdditionalAppBarIconsPreference = findPreference("display_additional_app_bar_icons");
70         final Preference displayWebpageImagesPreference = findPreference("display_webpage_images");
71
72         // Set dependencies.
73         domStoragePreference.setDependency("javascript_enabled");
74         torHomepagePreference.setDependency("proxy_through_orbot");
75         torSearchPreference.setDependency("proxy_through_orbot");
76         hideSystemBarsPreference.setDependency("full_screen_browsing_mode");
77
78         // Get strings from the preferences.
79         String torSearchString = savedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
80         String searchString = savedPreferences.getString("search", "https://duckduckgo.com/html/?q=");
81
82         // Get booleans from the preferences.
83         boolean javaScriptEnabledBoolean = savedPreferences.getBoolean("javascript_enabled", false);
84         boolean firstPartyCookiesEnabledBoolean = savedPreferences.getBoolean("first_party_cookies_enabled", false);
85         boolean thirdPartyCookiesEnabledBoolean = savedPreferences.getBoolean("third_party_cookies_enabled", false);
86         boolean proxyThroughOrbotBoolean = savedPreferences.getBoolean("proxy_through_orbot", false);
87         boolean fullScreenBrowsingModeBoolean = savedPreferences.getBoolean("full_screen_browsing_mode", false);
88         boolean hideSystemBarsBoolean = savedPreferences.getBoolean("hide_system_bars", false);
89
90         // Only enable `thirdPartyCookiesPreference` if `firstPartyCookiesEnabledBoolean` is `true` and API >= 21.
91         thirdPartyCookiesPreference.setEnabled(firstPartyCookiesEnabledBoolean && (Build.VERSION.SDK_INT >= 21));
92
93         // We need to inflated a `WebView` to get the default user agent.
94         LayoutInflater inflater = getActivity().getLayoutInflater();
95         // `@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.
96         @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
97         final WebView bareWebView = (WebView) bareWebViewLayout.findViewById(R.id.bare_webview);
98
99         // Set the current user-agent as the summary text for the "user_agent" preference when the preference screen is loaded.
100         switch (savedPreferences.getString("user_agent", "PrivacyBrowser/1.0")) {
101             case "WebView default user agent":
102                 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
103                 userAgentPreference.setSummary(bareWebView.getSettings().getUserAgentString());
104                 break;
105
106             case "Custom user agent":
107                 // We can't use the string from the array because it is referenced in code and can't be translated.
108                 userAgentPreference.setSummary(R.string.custom_user_agent);
109                 break;
110
111             default:
112                 // Display the user agent from the preference as the summary text.
113                 userAgentPreference.setSummary(savedPreferences.getString("user_agent", "PrivacyBrowser/1.0"));
114                 break;
115         }
116
117         // Set the summary text for "customUserAgentPreference" (the default is `PrivacyBrowser/1.0`) and enable it if `userAgentPreference` it set to `Custom user agent`.
118         customUserAgentPreference.setSummary(savedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0"));
119         customUserAgentPreference.setEnabled(userAgentPreference.getSummary().equals("Custom user agent"));
120
121
122         // 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`.
123         torHomepagePreference.setSummary(savedPreferences.getString("tor_homepage", "https://3g2upl4pq6kufc4m.onion"));
124
125
126         // 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=`
127         if (torSearchString.equals("Custom URL")) {
128             // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
129             torSearchPreference.setSummary(R.string.custom_url);
130         } else {
131             // Set the array value as the summary text.
132             torSearchPreference.setSummary(torSearchString);
133         }
134
135         // Set the summary text for `tor_search_custom_url`.  The default is `""`.
136         torSearchCustomURLPreference.setSummary(savedPreferences.getString("tor_search_custom_url", ""));
137
138         // Enable the Tor custom URL search options only if proxying through Orbot and the search is set to `Custom URL`.
139         torSearchCustomURLPreference.setEnabled(proxyThroughOrbotBoolean && torSearchString.equals("Custom URL"));
140
141
142         // 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=`.
143         if (searchString.equals("Custom URL")) {
144             // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
145             searchPreference.setSummary(R.string.custom_url);
146         } else {
147             // Set the array value as the summary text.
148             searchPreference.setSummary(searchString);
149         }
150
151         // Set the summary text for `search_custom_url` (the default is `""`) and enable it if `search` is set to `Custom URL`.
152         searchCustomURLPreference.setSummary(savedPreferences.getString("search_custom_url", ""));
153         searchCustomURLPreference.setEnabled(searchString.equals("Custom URL"));
154
155
156         // Enable `translucentNavigationBarPreference` only if full screen browsing mode is enabled and `hide_system_bars` is disabled.
157         translucentNavigationBarPreference.setEnabled(fullScreenBrowsingModeBoolean && !hideSystemBarsBoolean);
158
159
160         // Set the homepage URL as the summary text for the `Homepage` preference when the preference screen is loaded.  The default is `https://duckduckgo.com`.
161         homepagePreference.setSummary(savedPreferences.getString("homepage", "https://duckduckgo.com"));
162
163         // 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`.
164         defaultFontSizePreference.setSummary(savedPreferences.getString("default_font_size", "100") + "%%");
165
166
167         // Set the `javaScriptPreference` icon.
168         if (javaScriptEnabledBoolean) {
169             javaScriptPreference.setIcon(R.drawable.javascript_enabled);
170         } else {
171             javaScriptPreference.setIcon(R.drawable.privacy_mode);
172         }
173
174         // Set the `firstPartyCookiesPreference` icon.
175         if (firstPartyCookiesEnabledBoolean) {
176             firstPartyCookiesPreference.setIcon(R.drawable.cookies_enabled);
177         } else {
178             firstPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
179         }
180
181         // Set the `thirdPartyCookiesPreference` icon.
182         if (firstPartyCookiesEnabledBoolean && Build.VERSION.SDK_INT >= 21) {
183             if (thirdPartyCookiesEnabledBoolean) {
184                 thirdPartyCookiesPreference.setIcon(R.drawable.cookies_warning);
185             } else {
186                 thirdPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
187             }
188         } else {
189             thirdPartyCookiesPreference.setIcon(R.drawable.cookies_ghosted);
190         }
191
192         // Set the `domStoragePreference` icon.
193         if (javaScriptEnabledBoolean) {
194             if (savedPreferences.getBoolean("dom_storage_enabled", false)) {
195                 domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
196             } else {
197                 domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
198             }
199         } else {
200             domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
201         }
202
203         // Set the `saveFormDataPreference` icon.
204         if (savedPreferences.getBoolean("save_form_data_enabled", false)) {
205             saveFormDataPreference.setIcon(R.drawable.form_data_enabled);
206         } else {
207             saveFormDataPreference.setIcon(R.drawable.form_data_disabled);
208         }
209
210         // Set the `customUserAgentPreference` icon.
211         if (customUserAgentPreference.isEnabled()) {
212             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
213         } else {
214             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
215         }
216
217         // Set the `blockAdsPreference` icon.
218         if (savedPreferences.getBoolean("block_ads", true)) {
219             blockAdsPreference.setIcon(R.drawable.block_ads_enabled);
220         } else {
221             blockAdsPreference.setIcon(R.drawable.block_ads_disabled);
222         }
223
224         // Set the `incognitoModePreference` icon.
225         if (savedPreferences.getBoolean("incognito_mode", false)) {
226             incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
227         } else {
228             incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
229         }
230
231         // Set the `doNotTrackPreference` icon.
232         if (savedPreferences.getBoolean("do_not_track", false)) {
233             doNotTrackPreference.setIcon(R.drawable.do_not_track_enabled);
234         } else {
235             doNotTrackPreference.setIcon(R.drawable.do_not_track_disabled);
236         }
237
238         // Set the `proxyThroughOrbotPreference` icon.
239         if (proxyThroughOrbotBoolean) {
240             proxyThroughOrbotPreference.setIcon(R.drawable.orbot_enabled);
241         } else {
242             proxyThroughOrbotPreference.setIcon(R.drawable.orbot_disabled);
243         }
244
245         // Set the `torSearchPreference` and `torSearchCustomURLPreference` icons.
246         if (proxyThroughOrbotBoolean) {
247             // Set the `torHomepagePreference` and `torSearchPreference` icons.
248             torHomepagePreference.setIcon(R.drawable.home_enabled);
249             torSearchPreference.setIcon(R.drawable.search_enabled);
250
251             // Set the `torSearchCustomURLPreference` icon.
252             if (torSearchCustomURLPreference.isEnabled()) {
253                 torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
254             } else {
255                 torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_disabled);
256             }
257         } else {  // Proxy through Orbot is disabled.
258             torHomepagePreference.setIcon(R.drawable.home_ghosted);
259             torSearchPreference.setIcon(R.drawable.search_ghosted);
260             torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_ghosted);
261         }
262
263         // Set the `searchCustomURLPreference` icon.
264         if (searchCustomURLPreference.isEnabled()) {
265             searchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
266         } else {
267             searchCustomURLPreference.setIcon(R.drawable.search_custom_url_ghosted);
268         }
269
270         // Set the full screen browsing mode icons.
271         if (fullScreenBrowsingModeBoolean) {
272             // Set the `fullScreenBrowsingModePreference` icon.
273             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
274
275             if (hideSystemBarsBoolean) {
276                 // Set `hideSystemBarsPreference` to use the enabled icon.
277                 hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_enabled);
278
279                 // Set `translucentNavigationBarPreference` to use the ghosted icon.
280                 translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
281             } else {  // `hideSystemBarsBoolean` is false.
282                 // Set `hideSystemBarsPreference` to use the disabled icon.
283                 hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_disabled);
284
285                 // Set the correct icon for `translucentNavigationBarPreference`.
286                 if (savedPreferences.getBoolean("translucent_navigation_bar", true)) {
287                     translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_enabled);
288                 } else {
289                     translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_disabled);
290                 }
291             }
292         } else {  // `fullScreenBrowsingModeBoolean` is false.
293             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
294             hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_ghosted);
295             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
296         }
297
298         // Set the `swipeToRefreshPreference` icon.
299         if (savedPreferences.getBoolean("swipe_to_refresh", false)) {
300             swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
301         } else {
302             swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
303         }
304
305         // Set the `displayAdditionalAppBarIconsPreference` icon.
306         if (savedPreferences.getBoolean("display_additional_app_bar_icons", false)) {
307             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
308         } else {
309             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
310         }
311
312         // Set the `displayWebpageImagesPreference` icon.
313         if (savedPreferences.getBoolean("display_webpage_images", true)) {
314             displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
315         } else {
316             displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
317         }
318
319
320         // Listen for preference changes.
321         preferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
322             @Override
323             // Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled.  We know.
324             @SuppressLint("SetJavaScriptEnabled")
325             public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
326
327                 switch (key) {
328                     case "javascript_enabled":
329                         // Update the icons.
330                         if (sharedPreferences.getBoolean("javascript_enabled", false)) {
331                             // Update the icon for `javascript_enabled`.
332                             javaScriptPreference.setIcon(R.drawable.javascript_enabled);
333
334                             // Update the icon for `dom_storage_enabled`.
335                             if (sharedPreferences.getBoolean("dom_storage_enabled", false)) {
336                                 domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
337                             } else {
338                                 domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
339                             }
340                         } else {  // `javascript_enabled` is `false`.
341                             // Update the icon for `javascript_enabled`.
342                             javaScriptPreference.setIcon(R.drawable.privacy_mode);
343
344                             // Set the icon for `dom_storage_disabled` to be ghosted.
345                             domStoragePreference.setIcon(R.drawable.dom_storage_ghosted);
346                         }
347                         break;
348
349                     case "first_party_cookies_enabled":
350                         // Update the icons for `first_party_cookies_enabled` and `third_party_cookies_enabled`.
351                         if (sharedPreferences.getBoolean("first_party_cookies_enabled", false)) {
352                             // Set the icon for `first_party_cookies_enabled`.
353                             firstPartyCookiesPreference.setIcon(R.drawable.cookies_enabled);
354
355                             // Update the icon for `third_party_cookies_enabled`.
356                             if (Build.VERSION.SDK_INT >= 21) {
357                                 if (sharedPreferences.getBoolean("third_party_cookies_enabled", false)) {
358                                     thirdPartyCookiesPreference.setIcon(R.drawable.cookies_warning);
359                                 } else {
360                                     thirdPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
361                                 }
362                             } else {
363                                 thirdPartyCookiesPreference.setIcon(R.drawable.cookies_ghosted);
364                             }
365                         } else {  // `first_party_cookies_enabled` is `false`.
366                             // Update the icon for `first_party_cookies_enabled`.
367                             firstPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
368
369                             // Set the icon for `third_party_cookies_enabled` to be ghosted.
370                             thirdPartyCookiesPreference.setIcon(R.drawable.cookies_ghosted);
371                         }
372
373                         // Enable `third_party_cookies_enabled` if `first_party_cookies_enabled` is `true` and API >= 21.
374                         thirdPartyCookiesPreference.setEnabled(sharedPreferences.getBoolean("first_party_cookies_enabled", false) && (Build.VERSION.SDK_INT >= 21));
375                         break;
376
377                     case "third_party_cookies_enabled":
378                         // Update the icon.
379                         if (sharedPreferences.getBoolean("third_party_cookies_enabled", false)) {
380                             thirdPartyCookiesPreference.setIcon(R.drawable.cookies_warning);
381                         } else {
382                             thirdPartyCookiesPreference.setIcon(R.drawable.cookies_disabled);
383                         }
384                         break;
385
386                     case "dom_storage_enabled":
387                         // Update the icon.
388                         if (sharedPreferences.getBoolean("dom_storage_enabled", false)) {
389                             domStoragePreference.setIcon(R.drawable.dom_storage_enabled);
390                         } else {
391                             domStoragePreference.setIcon(R.drawable.dom_storage_disabled);
392                         }
393                         break;
394
395                     case "save_form_data_enabled":
396                         // Update the icon.
397                         if (sharedPreferences.getBoolean("save_form_data_enabled", false)) {
398                             saveFormDataPreference.setIcon(R.drawable.form_data_enabled);
399                         } else {
400                             saveFormDataPreference.setIcon(R.drawable.form_data_disabled);
401                         }
402
403                     case "user_agent":
404                         String userAgentString = sharedPreferences.getString("user_agent", "PrivacyBrowser/1.0");
405
406                         switch (userAgentString) {
407                             case "WebView default user agent":
408                                 // Display the user agent as the summary text for `userAgentPreference`.
409                                 userAgentPreference.setSummary(bareWebView.getSettings().getUserAgentString());
410
411                                 // Update `customUserAgentPreference`.
412                                 customUserAgentPreference.setEnabled(false);
413                                 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
414                                 break;
415
416                             case "Custom user agent":
417                                 // Display `Custom user agent` as the summary text for `userAgentPreference`.
418                                 userAgentPreference.setSummary(R.string.custom_user_agent);
419
420                                 // Update `customUserAgentPreference`.
421                                 customUserAgentPreference.setEnabled(true);
422                                 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled);
423                                 break;
424
425                             default:
426                                 // Display the user agent as the summary text for `userAgentPreference`.
427                                 userAgentPreference.setSummary(sharedPreferences.getString("user_agent", "PrivacyBrowser/1.0"));
428
429                                 // Update `customUserAgentPreference`.
430                                 customUserAgentPreference.setEnabled(false);
431                                 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted);
432                                 break;
433                         }
434                         break;
435
436                     case "custom_user_agent":
437                         // Set the new custom user agent as the summary text for `custom_user_agent`.  The default is `PrivacyBrowser/1.0`.
438                         customUserAgentPreference.setSummary(sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0"));
439                         break;
440
441                     case "block_ads":
442                         // Update the icon.
443                         if (sharedPreferences.getBoolean("block_ads", true)) {
444                             blockAdsPreference.setIcon(R.drawable.block_ads_enabled);
445                         } else {
446                             blockAdsPreference.setIcon(R.drawable.block_ads_disabled);
447                         }
448                         break;
449
450                     case "incognito_mode":
451                         // Update the icon.
452                         if (sharedPreferences.getBoolean("incognito_mode", false)) {
453                             incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled);
454                         } else {
455                             incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled);
456                         }
457                         break;
458
459                     case "do_not_track":
460                         // Update the icon.
461                         if (sharedPreferences.getBoolean("do_not_track", false)) {
462                             doNotTrackPreference.setIcon(R.drawable.do_not_track_enabled);
463                         } else {
464                             doNotTrackPreference.setIcon(R.drawable.do_not_track_disabled);
465                         }
466
467                         break;
468
469                     case "proxy_through_orbot":
470                         // Get current settings.
471                         boolean currentProxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
472                         String currentTorSearchString = sharedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
473
474                         // Enable the Tor custom URL search option only if `currentProxyThroughOrbot` is true and the search is set to `Custom URL`.
475                         torSearchCustomURLPreference.setEnabled(currentProxyThroughOrbot && currentTorSearchString.equals("Custom URL"));
476
477                         // Update the icons.
478                         if (currentProxyThroughOrbot) {
479                             // Set the `proxyThroughOrbotPreference`, `torHomepagePreference`, and `torSearchPreference` icons.
480                             proxyThroughOrbotPreference.setIcon(R.drawable.orbot_enabled);
481                             torHomepagePreference.setIcon(R.drawable.home_enabled);
482                             torSearchPreference.setIcon(R.drawable.search_enabled);
483
484                             // Set the `torSearchCustomURLPreference` icon.
485                             if (torSearchCustomURLPreference.isEnabled()) {
486                                 torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
487                             } else {
488                                 torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_disabled);
489                             }
490                         } else {  // Proxy through Orbot is disabled.
491                             proxyThroughOrbotPreference.setIcon(R.drawable.orbot_disabled);
492                             torHomepagePreference.setIcon(R.drawable.home_ghosted);
493                             torSearchPreference.setIcon(R.drawable.search_ghosted);
494                             torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_ghosted);
495                         }
496                         break;
497
498                     case "tor_homepage":
499                         // Set the new tor homepage URL as the summary text for the `tor_homepage` preference.  The default is DuckDuckGo:  `https://3g2upl4pq6kufc4m.onion`.
500                         torHomepagePreference.setSummary(sharedPreferences.getString("tor_homepage", "https://3g2upl4pq6kufc4m.onion"));
501                         break;
502
503                     case "tor_search":
504                         // Get the present search string.
505                         String presentTorSearchString = sharedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
506
507                         // Update the preferences.
508                         if (presentTorSearchString.equals("Custom URL")) {
509                             // Use `R.string.custom_url`, which is translated, as the summary instead of the array value, which isn't.
510                             torSearchPreference.setSummary(R.string.custom_url);
511
512                             // Update `torSearchCustomURLPreference`.
513                             torSearchCustomURLPreference.setEnabled(true);
514                             torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
515                         } else {
516                             // Set the array value as the summary text.
517                             torSearchPreference.setSummary(presentTorSearchString);
518
519                             // Update `torSearchCustomURLPreference`.
520                             torSearchCustomURLPreference.setEnabled(false);
521                             torSearchCustomURLPreference.setIcon(R.drawable.search_custom_url_disabled);
522                         }
523                         break;
524
525                     case "tor_search_custom_url":
526                         // Set the summary text for `tor_search_custom_url`.
527                         torSearchCustomURLPreference.setSummary(sharedPreferences.getString("tor_search_custom_url", ""));
528                         break;
529
530                     case "search":
531                         // Store the new search string.
532                         String newSearchString = sharedPreferences.getString("search", "https://duckduckgo.com/html/?q=");
533
534                         // Update `searchPreference` and `searchCustomURLPreference`.
535                         if (newSearchString.equals("Custom URL")) {  // `Custom URL` is selected.
536                             // Set the summary text to `R.string.custom_url`, which is translated.
537                             searchPreference.setSummary(R.string.custom_url);
538
539                             // Update `searchCustomURLPreference`.
540                             searchCustomURLPreference.setEnabled(true);
541                             searchCustomURLPreference.setIcon(R.drawable.search_custom_url_enabled);
542                         } else {  // `Custom URL` is not selected.
543                             // Set the summary text to `newSearchString`.
544                             searchPreference.setSummary(newSearchString);
545
546                             // Update `searchCustomURLPreference`.
547                             searchCustomURLPreference.setEnabled(false);
548                             searchCustomURLPreference.setIcon(R.drawable.search_custom_url_ghosted);
549                         }
550                         break;
551
552                     case "search_custom_url":
553                         // Set the new custom search URL as the summary text for `search_custom_url`.  The default is `""`.
554                         searchCustomURLPreference.setSummary(sharedPreferences.getString("search_custom_url", ""));
555                         break;
556
557                     case "full_screen_browsing_mode":
558                         if (sharedPreferences.getBoolean("full_screen_browsing_mode", false)) {
559                             // Set `fullScreenBrowsingModePreference` to use the enabled icon.
560                             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled);
561
562                             if (sharedPreferences.getBoolean("hide_system_bars", false)) {
563                                 // Set `hideSystemBarsPreference` to use the enabled icon.
564                                 hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_enabled);
565
566                                 // Update `translucentNavigationBarPreference`.
567                                 translucentNavigationBarPreference.setEnabled(false);
568                                 translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
569                             } else {  // `hide_system_bars` is false.
570                                 // Set `hideSystemBarsPreference` to use the disabled icon.
571                                 hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_disabled);
572
573                                 // Update `translucentNavigationBarPreference`.
574                                 translucentNavigationBarPreference.setEnabled(true);
575                                 if (sharedPreferences.getBoolean("translucent_navigation_bar", true)) {
576                                     translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_enabled);
577                                 } else {
578                                     translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_disabled);
579                                 }
580                             }
581                         } else {  // `full_screen_browsing_mode` is false.
582                             // Disable `translucentNavigationBarPreference`.
583                             translucentNavigationBarPreference.setEnabled(false);
584
585                             // Update the icons.
586                             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled);
587                             hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_ghosted);
588                             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
589                         }
590                         break;
591
592                     case "hide_system_bars":
593                         if (sharedPreferences.getBoolean("hide_system_bars", false)) {
594                             // Set `hideSystemBarsPreference` to use the enabled icon.
595                             hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_enabled);
596
597                             // Update `translucentNavigationBarPreference`.
598                             translucentNavigationBarPreference.setEnabled(false);
599                             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_ghosted);
600                         } else {  // `hide_system_bars` is false.
601                             // Set `hideSystemBarsPreference` to use the disabled icon.
602                             hideSystemBarsPreference.setIcon(R.drawable.hide_system_bars_disabled);
603
604                             // Update `translucentNavigationBarPreference`.
605                             translucentNavigationBarPreference.setEnabled(true);
606                             if (sharedPreferences.getBoolean("translucent_navigation_bar", true)) {
607                                 translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_enabled);
608                             } else {
609                                 translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_disabled);
610                             }
611                         }
612                         break;
613
614                     case "translucent_navigation_bar":
615                         // Update the icon.
616                         if (sharedPreferences.getBoolean("translucent_navigation_bar", true)) {
617                             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_enabled);
618                         } else {
619                             translucentNavigationBarPreference.setIcon(R.drawable.translucent_bar_disabled);
620                         }
621                         break;
622
623                     case "homepage":
624                         // Set the new homepage URL as the summary text for the Homepage preference.  The default is `https://www.duckduckgo.com`.
625                         homepagePreference.setSummary(sharedPreferences.getString("homepage", "https://www.duckduckgo.com"));
626                         break;
627
628                     case "default_font_size":
629                         // Update the summary text of `default_font_size`.
630                         defaultFontSizePreference.setSummary(sharedPreferences.getString("default_font_size", "100") + "%%");
631                         break;
632
633                     case "swipe_to_refresh":
634                         // Update the icon.
635                         if (sharedPreferences.getBoolean("swipe_to_refresh", false)) {
636                             swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled);
637                         } else {
638                             swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled);
639                         }
640                         break;
641
642                     case "display_additional_app_bar_icons":
643                         // Update the icon.
644                         if (sharedPreferences.getBoolean("display_additional_app_bar_icons", false)) {
645                             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled);
646                         } else {
647                             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled);
648                         }
649                         break;
650
651                     case "display_webpage_images":
652                         // Update the icon.
653                         if (sharedPreferences.getBoolean("display_webpage_images", true)) {
654                             displayWebpageImagesPreference.setIcon(R.drawable.images_enabled);
655                         } else {
656                             displayWebpageImagesPreference.setIcon(R.drawable.images_disabled);
657                         }
658                         break;
659
660                     default:
661                         // If no match, do nothing.
662                         break;
663                 }
664             }
665         };
666
667         // Register the listener.
668         savedPreferences.registerOnSharedPreferenceChangeListener(preferencesListener);
669     }
670
671     // 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
672     // even while running in the foreground.
673     @Override
674     public void onPause() {
675         super.onPause();
676         savedPreferences.unregisterOnSharedPreferenceChangeListener(preferencesListener);
677     }
678
679     @Override
680     public void onResume() {
681         super.onResume();
682         savedPreferences.registerOnSharedPreferenceChangeListener(preferencesListener);
683     }
684 }