Niedzielski has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/218815

Change subject: WIP: hygiene: refactor shared preferences access
......................................................................

WIP: hygiene: refactor shared preferences access

Change-Id: I5d2de61ae0adf163e6bbb39337236d1d8c592c84
---
M wikipedia/AndroidManifest.xml
M wikipedia/res/values/preference_keys.xml
M wikipedia/res/xml/preferences.xml
M wikipedia/src/main/java/org/wikipedia/RemoteConfig.java
M wikipedia/src/main/java/org/wikipedia/SharedPreferenceCookieManager.java
M wikipedia/src/main/java/org/wikipedia/Utils.java
M wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
M wikipedia/src/main/java/org/wikipedia/editing/EditTokenStorage.java
M wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java
M wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageState.java
M wikipedia/src/main/java/org/wikipedia/login/UserInfoStorage.java
M wikipedia/src/main/java/org/wikipedia/nearby/NearbyFragment.java
M wikipedia/src/main/java/org/wikipedia/onboarding/OnboardingActivity.java
M wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
M wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
M wikipedia/src/main/java/org/wikipedia/page/SectionsFetchTask.java
M wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
M 
wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
M wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java
M wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
M wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewVersion.java
M wikipedia/src/main/java/org/wikipedia/savedpages/SavedPagesFragment.java
M wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
D wikipedia/src/main/java/org/wikipedia/settings/PrefKeys.java
D wikipedia/src/main/java/org/wikipedia/settings/PreferenceUtil.java
M wikipedia/src/main/java/org/wikipedia/settings/Prefs.java
A wikipedia/src/main/java/org/wikipedia/settings/PrefsIoUtil.java
M wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java
M wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java
M wikipedia/src/main/java/org/wikipedia/theme/ExperimentalPageLoadChooser.java
M wikipedia/src/main/java/org/wikipedia/theme/ThemeChooserDialog.java
M wikipedia/src/main/java/org/wikipedia/util/StringUtil.java
32 files changed, 542 insertions(+), 430 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/apps/android/wikipedia 
refs/changes/15/218815/1

diff --git a/wikipedia/AndroidManifest.xml b/wikipedia/AndroidManifest.xml
index b8531da..dddf1bb 100644
--- a/wikipedia/AndroidManifest.xml
+++ b/wikipedia/AndroidManifest.xml
@@ -39,7 +39,7 @@
         The following is used for determining the distribution channel.
         Set "value" to "Google Play" for Google Play Store.
         -->
-        <meta-data android:name="@string/preference_channel" 
android:value="@string/channel" />
+        <meta-data android:name="@string/preference_key_app_channel" 
android:value="@string/channel" />
         <!-- Don't delete the meta-data field above -->
 
         <activity android:name=".page.PageActivity"
diff --git a/wikipedia/res/values/preference_keys.xml 
b/wikipedia/res/values/preference_keys.xml
index 33cb005..d0fcc68 100644
--- a/wikipedia/res/values/preference_keys.xml
+++ b/wikipedia/res/values/preference_keys.xml
@@ -1,25 +1,27 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources xmlns:tools="http://schemas.android.com/tools"; 
tools:ignore="MissingTranslation">
     <string name="preference_key_language">content_language</string>
-    <string name="preference_cookie_domains">cookie_domains</string>
-    <string 
name="preference_cookies_for_domain">cookies_for_domain_%1$s</string>
-    <string name="preference_edittoken_wikis">edittoken_wikis</string>
-    <string 
name="preference_edittoken_for_wiki">edittoken_for_wiki_%1$s</string>
+    <string name="preference_key_cookie_domains">cookie_domains</string>
+    <string 
name="preference_key_cookies_for_domain_format">cookies_for_domain_%1$s</string>
+    <string name="preference_key_edittoken_wikis">edittoken_wikis</string>
+    <string 
name="preference_key_edittoken_for_wiki_format">edittoken_for_wiki_%1$s</string>
     <string 
name="preference_key_zero_interstitial">zero_warn_when_leaving</string>
     <string name="preference_key_remote_config">remote_config</string>
     <string 
name="preference_key_eventlogging_opt_in">eventlogging_opt_in</string>
-    <string 
name="preference_key_styles_last_updated">styles_last_updated</string>
     <string name="preference_key_version">app_version</string>
     <string name="preference_key_feedback">send_feedback</string>
     <string name="preference_key_logout">log_out</string>
-    <string 
name="preference_reading_app_install_id">readingAppInstallID</string>
-    <string name="preference_feature_flag_id">featureFlagID</string>
-    <string name="preference_onboard">onboard</string>
-    <string name="preference_text_size_multiplier">textSizeMultiplier</string>
-    <string name="preference_color_theme">colorTheme</string>
-    <string name="preference_channel">channel</string>
-    <string name="preference_language_mru">languageMru</string>
-    <string name="preference_know_toc_drawer">knowToC</string>
-    <string name="preference_show_images">showImages</string>
-    <string name="preference_exp_page_load">expPageLoad</string>
+    <string 
name="preference_key_reading_app_install_id">readingAppInstallID</string>
+    <string name="preference_key_feature_flag_id">featureFlagID</string>
+    <string name="preference_key_onboard">onboard</string>
+    <string 
name="preference_key_text_size_multiplier">textSizeMultiplier</string>
+    <string name="preference_key_color_theme">colorTheme</string>
+    <string name="preference_key_app_channel">channel</string>
+    <string name="preference_key_language_mru">languageMru</string>
+    <string name="preference_key_know_toc_drawer">knowToC</string>
+    <string name="preference_key_show_images">showImages</string>
+    <string name="preference_key_exp_page_load">expPageLoad</string>
+    <string name="preference_key_login_username">username</string>
+    <string name="preference_key_login_password">password</string>
+    <string name="preference_key_login_user_id">userID</string>
 </resources>
diff --git a/wikipedia/res/xml/preferences.xml 
b/wikipedia/res/xml/preferences.xml
index 0ab5472..e847076 100644
--- a/wikipedia/res/xml/preferences.xml
+++ b/wikipedia/res/xml/preferences.xml
@@ -13,7 +13,7 @@
             android:summary="@string/preference_summary_eventlogging_opt_in"
             />
         <org.wikipedia.settings.CheckBoxPreferenceMultiLine
-            android:key="@string/preference_show_images"
+            android:key="@string/preference_key_show_images"
             android:defaultValue="true"
             android:title="@string/preference_title_show_images"
             android:summary="@string/preference_summary_show_images"
diff --git a/wikipedia/src/main/java/org/wikipedia/RemoteConfig.java 
b/wikipedia/src/main/java/org/wikipedia/RemoteConfig.java
index f0a4b16..c440be1 100644
--- a/wikipedia/src/main/java/org/wikipedia/RemoteConfig.java
+++ b/wikipedia/src/main/java/org/wikipedia/RemoteConfig.java
@@ -1,28 +1,18 @@
 package org.wikipedia;
 
-import android.content.SharedPreferences;
 import org.json.JSONException;
 import org.json.JSONObject;
-import org.wikipedia.settings.PrefKeys;
+import org.wikipedia.settings.Prefs;
 
 /**
  * Store for config values that are retreived from a server,
  * and refreshed periodically.
  */
 public class RemoteConfig {
-
-    private final SharedPreferences prefs;
-
     private JSONObject curConfig;
 
-    public RemoteConfig(SharedPreferences prefs) {
-        this.prefs = prefs;
-    }
-
     public void updateConfig(JSONObject newConfig) {
-        prefs.edit()
-                .putString(PrefKeys.getRemoteConfig(), newConfig.toString())
-                .apply();
+        Prefs.setRemoteConfigJson(newConfig.toString());
         curConfig = newConfig;
     }
 
@@ -30,7 +20,7 @@
         if (curConfig == null) {
             try {
                 // If there's no pref set, just give back the empty JSON Object
-                curConfig = new 
JSONObject(prefs.getString(PrefKeys.getRemoteConfig(), "{}"));
+                curConfig = new JSONObject(Prefs.getRemoteConfigJson());
             } catch (JSONException e) {
                 // This shouldn't be happening, and if it does I'd like a 
crash report
                 throw new RuntimeException(e);
diff --git 
a/wikipedia/src/main/java/org/wikipedia/SharedPreferenceCookieManager.java 
b/wikipedia/src/main/java/org/wikipedia/SharedPreferenceCookieManager.java
index 86a375c..1e77a6e 100644
--- a/wikipedia/src/main/java/org/wikipedia/SharedPreferenceCookieManager.java
+++ b/wikipedia/src/main/java/org/wikipedia/SharedPreferenceCookieManager.java
@@ -1,8 +1,7 @@
 package org.wikipedia;
 
-import android.content.SharedPreferences;
-import android.text.TextUtils;
-import org.wikipedia.settings.PrefKeys;
+import org.wikipedia.settings.Prefs;
+import org.wikipedia.util.StringUtil;
 
 import java.io.IOException;
 import java.net.CookieManager;
@@ -10,7 +9,6 @@
 import java.net.HttpCookie;
 import java.net.URI;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -18,16 +16,14 @@
 import java.util.Map;
 
 public class SharedPreferenceCookieManager extends CookieManager {
+    private static final String DELIMITER = ";";
 
     private final HashMap<String, HashMap<String, String>> cookieJar = new 
HashMap<>();
-    private final SharedPreferences prefs;
 
-    public SharedPreferenceCookieManager(SharedPreferences prefs) {
-        this.prefs = prefs;
-        List<String> domains = 
makeList(prefs.getString(PrefKeys.getCookieDomainsKey(), ""));
+    public SharedPreferenceCookieManager() {
+        List<String> domains = makeList(Prefs.getCookieDomains());
         for (String domain: domains) {
-            String key = String.format(PrefKeys.getCookiesForDomain(), domain);
-            String cookies = prefs.getString(key, "");
+            String cookies = Prefs.getCookiesForDomain(domain);
             cookieJar.put(domain, makeCookieMap(makeList(cookies)));
         }
     }
@@ -90,15 +86,11 @@
             }
         }
 
-        SharedPreferences.Editor editor = prefs.edit();
-        editor.putString(PrefKeys.getCookieDomainsKey(), 
makeString(cookieJar.keySet()));
+        Prefs.setCookieDomains(makeString(cookieJar.keySet()));
 
         for (String domain : domainsModified) {
-            String prefKey = String.format(PrefKeys.getCookiesForDomain(), 
domain);
-            editor.putString(prefKey, 
makeString(makeCookieList(cookieJar.get(domain))));
-
+            Prefs.setCookiesForDomain(domain, 
makeString(makeCookieList(cookieJar.get(domain))));
         }
-        editor.apply();
     }
 
     @Override
@@ -108,13 +100,10 @@
     }
 
     public void clearAllCookies() {
-        SharedPreferences.Editor editor = prefs.edit();
         for (String domain: cookieJar.keySet()) {
-            String key = String.format(PrefKeys.getCookiesForDomain(), domain);
-            editor.remove(key);
+            Prefs.removeCookiesForDomain(domain);
         }
-        editor.remove(PrefKeys.getCookieDomainsKey());
-        editor.apply();
+        Prefs.setCookieDomains(null);
         cookieJar.clear();
     }
 
@@ -139,10 +128,10 @@
     }
 
     private String makeString(Iterable<String> list) {
-        return TextUtils.join(";", list);
+        return StringUtil.listToDelimitedString(list, DELIMITER);
     }
 
     private List<String> makeList(String str) {
-        return Arrays.asList(TextUtils.split(str, ";"));
+        return StringUtil.delimiterStringToList(str, DELIMITER);
     }
 }
diff --git a/wikipedia/src/main/java/org/wikipedia/Utils.java 
b/wikipedia/src/main/java/org/wikipedia/Utils.java
index bdb3c26..a413c9a 100644
--- a/wikipedia/src/main/java/org/wikipedia/Utils.java
+++ b/wikipedia/src/main/java/org/wikipedia/Utils.java
@@ -5,14 +5,12 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.TypedArray;
 import android.net.Uri;
 import android.os.Looper;
-import android.preference.PreferenceManager;
 import android.text.Html;
 import android.text.InputType;
 import android.text.format.DateUtils;
@@ -31,7 +29,7 @@
 import org.json.JSONObject;
 import org.wikipedia.bridge.CommunicationBridge;
 import org.wikipedia.interlanguage.LanguageUtil;
-import org.wikipedia.settings.PrefKeys;
+import org.wikipedia.settings.Prefs;
 import org.wikipedia.util.ApiUtil;
 import org.wikipedia.util.ShareUtils;
 
@@ -50,7 +48,11 @@
 import java.security.NoSuchAlgorithmException;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
 
 /**
  * Contains utility methods that Java doesn't have because we can't make code 
look too good, can we?
@@ -321,8 +323,7 @@
 
     public static void handleExternalLink(final Context context, final Uri 
uri) {
         if 
(WikipediaApp.getInstance().getWikipediaZeroHandler().isZeroEnabled()) {
-            SharedPreferences sharedPref = 
PreferenceManager.getDefaultSharedPreferences(context);
-            if (sharedPref.getBoolean(PrefKeys.getZeroInterstitial(), true)) {
+            if (Prefs.isShowZeroInterstitialEnabled()) {
                 AlertDialog.Builder alert = new AlertDialog.Builder(context);
                 
alert.setTitle(context.getString(R.string.zero_interstitial_title));
                 
alert.setMessage(context.getString(R.string.zero_interstitial_leave_app));
@@ -580,9 +581,9 @@
      */
     private static String getChannelDescriptor(Context ctx) {
         try {
-            ApplicationInfo a = ctx.getPackageManager()
+            ApplicationInfo info = ctx.getPackageManager()
                     .getApplicationInfo(BuildConfig.APPLICATION_ID, 
PackageManager.GET_META_DATA);
-            String channel = a.metaData.getString(PrefKeys.getChannel());
+            String channel = info.metaData.getString(Prefs.getAppChannelKey());
             return channel != null ? channel : "";
         } catch (Throwable t) {
             // oops
@@ -593,20 +594,18 @@
     /**
      * Sets the distribution channel for the app into SharedPreferences
      */
-    private static void setChannel(Context ctx, String channel) {
-        SharedPreferences prefs = 
PreferenceManager.getDefaultSharedPreferences(ctx);
-        prefs.edit().putString(PrefKeys.getChannel(), channel).apply();
+    private static void setChannel(String channel) {
+        Prefs.setAppChannel(channel);
     }
 
     /**
      * Gets the distribution channel for the app from SharedPreferences
      */
     public static String getChannel(Context ctx) {
-        SharedPreferences prefs = 
PreferenceManager.getDefaultSharedPreferences(ctx);
-        String channel = prefs.getString(PrefKeys.getChannel(), null);
+        String channel = Prefs.getAppChannel();
         if (channel == null) {
             channel = getChannelDescriptor(ctx);
-            setChannel(ctx, channel);
+            setChannel(channel);
         }
         return channel;
     }
diff --git a/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java 
b/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
index 2e5a7ed..c34a26f 100644
--- a/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
+++ b/wikipedia/src/main/java/org/wikipedia/WikipediaApp.java
@@ -1,13 +1,11 @@
 package org.wikipedia;
 
 import android.app.Application;
-import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
-import android.preference.PreferenceManager;
 import android.support.annotation.IntRange;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
@@ -43,7 +41,7 @@
 import org.wikipedia.savedpages.SavedPagePersister;
 import org.wikipedia.search.RecentSearch;
 import org.wikipedia.search.RecentSearchPersister;
-import org.wikipedia.settings.PrefKeys;
+import org.wikipedia.settings.Prefs;
 import org.wikipedia.util.ApiUtil;
 import org.wikipedia.zero.WikipediaZeroHandler;
 
@@ -151,12 +149,6 @@
         return pageCache;
     }
 
-    /**
-     * Preference manager for storing things like the app's install IDs for 
EventLogging, theme,
-     * font size, etc.
-     */
-    private SharedPreferences prefs;
-
     public WikipediaApp() {
         INSTANCE = this;
     }
@@ -188,9 +180,6 @@
         final Resources resources = getResources();
         ViewAnimations.init(resources);
         screenDensity = resources.getDisplayMetrics().density;
-
-        this.prefs = PreferenceManager.getDefaultSharedPreferences(this);
-        PrefKeys.initPreferenceKeys(resources);
 
         appLanguageState = new AppLanguageState(this);
 
@@ -378,7 +367,7 @@
     private RemoteConfig remoteConfig;
     public RemoteConfig getRemoteConfig() {
         if (remoteConfig == null) {
-            remoteConfig = new RemoteConfig(prefs);
+            remoteConfig = new RemoteConfig();
         }
         return remoteConfig;
     }
@@ -394,7 +383,7 @@
     private SharedPreferenceCookieManager cookieManager;
     public SharedPreferenceCookieManager getCookieManager() {
         if (cookieManager == null) {
-            cookieManager = new SharedPreferenceCookieManager(prefs);
+            cookieManager = new SharedPreferenceCookieManager();
         }
         return cookieManager;
     }
@@ -402,7 +391,7 @@
     private UserInfoStorage userInfoStorage;
     public UserInfoStorage getUserInfoStorage() {
         if (userInfoStorage == null) {
-            userInfoStorage = new UserInfoStorage(prefs);
+            userInfoStorage = new UserInfoStorage();
         }
         return userInfoStorage;
     }
@@ -422,7 +411,12 @@
      * @return Unique install ID for this app.
      */
     public String getAppInstallID() {
-        return getAppInstallIDForFeature(PrefKeys.getAppInstallID());
+        String id = Prefs.getAppInstallId();
+        if (id == null) {
+            id = UUID.randomUUID().toString();
+            Prefs.setAppInstallId(id);
+        }
+        return id;
     }
 
     /**
@@ -446,33 +440,16 @@
     @IntRange(from = 0)
     private int getFeatureFlagID() {
         int featureFlagID;
-        if (prefs.contains(PrefKeys.getFeatureFlagID())) {
-            featureFlagID = prefs.getInt(PrefKeys.getFeatureFlagID(), 0);
+        if (Prefs.hasFeatureFlagId()) {
+            featureFlagID = Prefs.getFeatureFlagId();
         } else {
             // generate a random number in the range [0, max-int)
             featureFlagID = new Random().nextInt(Integer.MAX_VALUE);
-            prefs.edit().putInt(PrefKeys.getFeatureFlagID(), 
featureFlagID).apply();
+            Prefs.setFeatureFlagId(featureFlagID);
         }
         // make sure the number is positive by taking away the sign bit
         // (will only apply to previously-generated values that happened to be 
negative)
         return featureFlagID & Integer.MAX_VALUE;
-    }
-
-    /**
-     * Returns the unique app install ID for a feature. The app install ID is 
used to track unique
-     * users of each feature for the purpose of improving the app's user 
experience.
-     * @param  prefKey a key from PrefKeys for a feature with a unique app 
install ID
-     * @return         the unique app install ID of the specified feature
-     */
-    private String getAppInstallIDForFeature(String prefKey) {
-        String installID;
-        if (prefs.contains(prefKey)) {
-            installID = prefs.getString(prefKey, null);
-        } else {
-            installID = UUID.randomUUID().toString();
-            prefs.edit().putString(prefKey, installID).apply();
-        }
-        return installID;
     }
 
     /**
@@ -482,8 +459,9 @@
      */
     public int getCurrentTheme() {
         if (currentTheme == 0) {
-            currentTheme = prefs.getInt(PrefKeys.getColorTheme(), THEME_LIGHT);
+            currentTheme = Prefs.getColorThemeResourceId();
             if (currentTheme != THEME_LIGHT && currentTheme != THEME_DARK) {
+                // TODO: store something we can deserialize more reliably.
                 currentTheme = THEME_LIGHT;
             }
         }
@@ -499,7 +477,7 @@
             return;
         }
         currentTheme = newTheme;
-        prefs.edit().putInt(PrefKeys.getColorTheme(), currentTheme).apply();
+        Prefs.setColorThemeResourceId(currentTheme);
         bus.post(new ThemeChangeEvent());
     }
 
@@ -535,7 +513,7 @@
     }
 
     public int getFontSizeMultiplier() {
-        return prefs.getInt(PrefKeys.getTextSizeMultiplier(), 0);
+        return Prefs.getTextSizeMultiplier();
     }
 
     public void setFontSizeMultiplier(int multiplier) {
@@ -544,7 +522,7 @@
         } else if (multiplier > FONT_SIZE_MULTIPLIER_MAX) {
             multiplier = FONT_SIZE_MULTIPLIER_MAX;
         }
-        prefs.edit().putInt(PrefKeys.getTextSizeMultiplier(), 
multiplier).apply();
+        Prefs.setTextSizeMultiplier(multiplier);
         bus.post(new ChangeTextSizeEvent());
     }
 
@@ -555,8 +533,8 @@
      * @return Actual current size of the font.
      */
     public float getFontSize(Window window) {
-        int multiplier = prefs.getInt(PrefKeys.getTextSizeMultiplier(), 0);
-        return Utils.getFontSizeFromSp(window, 
getResources().getDimension(R.dimen.textSize)) * (1.0f + multiplier * 
FONT_SIZE_FACTOR);
+        return Utils.getFontSizeFromSp(window,
+                getResources().getDimension(R.dimen.textSize)) * (1.0f + 
getFontSizeMultiplier() * FONT_SIZE_FACTOR);
     }
 
     /**
@@ -565,11 +543,11 @@
      * @return A boolean that is true if EventLogging is enabled, and false if 
it is not.
      */
     public boolean isEventLoggingEnabled() {
-        return prefs.getBoolean(PrefKeys.getEventLoggingEnabled(), true);
+        return Prefs.isEventLoggingEnabled();
     }
 
-    public boolean showImages() {
-        return prefs.getBoolean(PrefKeys.getShowImages(), true);
+    public boolean isImageDownloadEnabled() {
+        return Prefs.isImageDownloadEnabled();
     }
 
     public void resetSite() {
diff --git 
a/wikipedia/src/main/java/org/wikipedia/editing/EditTokenStorage.java 
b/wikipedia/src/main/java/org/wikipedia/editing/EditTokenStorage.java
index 9aedbee..978a814 100644
--- a/wikipedia/src/main/java/org/wikipedia/editing/EditTokenStorage.java
+++ b/wikipedia/src/main/java/org/wikipedia/editing/EditTokenStorage.java
@@ -1,20 +1,19 @@
 package org.wikipedia.editing;
 
 import android.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-import android.text.TextUtils;
+
 import org.wikipedia.Site;
 import org.wikipedia.Utils;
-import org.wikipedia.settings.PrefKeys;
+import org.wikipedia.settings.Prefs;
+import org.wikipedia.util.StringUtil;
 
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 
 public class EditTokenStorage {
+    private static final String DELIMITER = ";";
+
     private final HashMap<String, String> tokenJar = new HashMap<>();
-    private final SharedPreferences prefs;
     private final Context context;
 
     public interface TokenRetrievedCallback {
@@ -24,11 +23,9 @@
 
     public EditTokenStorage(Context context) {
         this.context = context;
-        this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
-        List<String> wikis = 
makeList(prefs.getString(PrefKeys.getEditTokenWikis(), ""));
+        List<String> wikis = makeList(Prefs.getEditTokenWikis());
         for (String wiki: wikis) {
-            String key = String.format(PrefKeys.getEditTokenForWiki(), wiki);
-            tokenJar.put(wiki, prefs.getString(key, null));
+            tokenJar.put(wiki, Prefs.getEditTokenForWiki(wiki));
         }
     }
 
@@ -57,31 +54,25 @@
     }
 
     public void clearAllTokens() {
-        SharedPreferences.Editor editor = prefs.edit();
-        for (String domain: tokenJar.keySet()) {
-            String key = String.format(PrefKeys.getEditTokenForWiki(), domain);
-            editor.remove(key);
+        for (String wiki : tokenJar.keySet()) {
+            Prefs.removeEditTokenForWiki(wiki);
         }
-        editor.remove(PrefKeys.getEditTokenWikis());
-        editor.apply();
+        Prefs.setEditTokenWikis(null);
         tokenJar.clear();
     }
 
     private void updatePrefs(String wiki, String token) {
         tokenJar.put(wiki, token);
         String wikisList = makeString(tokenJar.keySet());
-        String wikiKey = String.format(PrefKeys.getEditTokenForWiki(), wiki);
-        prefs.edit()
-                .putString(PrefKeys.getEditTokenWikis(), wikisList)
-                .putString(wikiKey, token)
-                .apply();
+        Prefs.setEditTokenWikis(wikisList);
+        Prefs.setEditTokenForWiki(wiki, token);
     }
 
     private String makeString(Iterable<String> list) {
-        return TextUtils.join(";", list);
+        return StringUtil.listToDelimitedString(list, DELIMITER);
     }
 
     private List<String> makeList(String str) {
-        return Arrays.asList(TextUtils.split(str, ";"));
+        return StringUtil.delimiterStringToList(str, DELIMITER);
     }
 }
diff --git a/wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java 
b/wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java
index 1b70aca..21184ca 100644
--- a/wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java
@@ -289,7 +289,7 @@
             source.setImageResource(getImageForSource(entry.getSource()));
             view.setTag(entry);
 
-            if (app.showImages()) {
+            if (app.isImageDownloadEnabled()) {
                 Picasso.with(getActivity())
                        
.load(cursor.getString(HistoryEntryContentProvider.COL_INDEX_IMAGE))
                        .placeholder(R.drawable.ic_pageimage_placeholder)
diff --git 
a/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageState.java 
b/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageState.java
index 04c9308..3a089c4 100644
--- a/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageState.java
+++ b/wikipedia/src/main/java/org/wikipedia/interlanguage/AppLanguageState.java
@@ -3,13 +3,12 @@
 import android.content.Context;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.text.TextUtils;
 
 import org.wikipedia.R;
-import org.wikipedia.settings.PreferenceUtil;
+import org.wikipedia.settings.Prefs;
+import org.wikipedia.util.StringUtil;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -42,7 +41,7 @@
     public AppLanguageState(@NonNull Context context) {
         this.context = context;
         appLanguageLookUpTable = new AppLanguageLookUpTable(context);
-        appLanguageCode = PreferenceUtil.getAppLanguageCode();
+        appLanguageCode = Prefs.getAppLanguageCode();
         mruLanguageCodes = unmarshalMruLanguageCodes();
     }
 
@@ -58,7 +57,7 @@
 
     public void setAppLanguageCode(@Nullable String code) {
         appLanguageCode = code;
-        PreferenceUtil.setAppLanguageCode(code);
+        Prefs.setAppLanguageCode(code);
     }
 
     public boolean isSystemLanguageEnabled() {
@@ -91,7 +90,7 @@
         List<String> codes = getMruLanguageCodes();
         codes.remove(code);
         codes.add(0, code);
-        PreferenceUtil.setMruLanguageCodes(listToCsv(codes));
+        Prefs.setMruLanguageCodeCsv(StringUtil.listToCsv(codes));
     }
 
     /** @return All app supported languages in MRU order. */
@@ -139,24 +138,13 @@
         // Null value is used to indicate that system language should be used.
         String systemLanguageCodeString = String.valueOf(SYSTEM_LANGUAGE_CODE);
 
-        String csv = defaultIfNull(PreferenceUtil.getMruLanguageCodes(), 
systemLanguageCodeString);
+        String csv = defaultIfNull(Prefs.getMruLanguageCodeCsv(), 
systemLanguageCodeString);
 
-        List<String> list = new ArrayList<>(csvToList(csv));
+        List<String> list = new ArrayList<>(StringUtil.csvToList(csv));
 
         Collections.replaceAll(list, systemLanguageCodeString, 
SYSTEM_LANGUAGE_CODE);
 
         return list;
-    }
-
-    @NonNull
-    private String listToCsv(@NonNull List<String> list) {
-        return TextUtils.join(",", list);
-    }
-
-    /** @return Nonnull immutable list. */
-    @NonNull
-    private List<String> csvToList(@NonNull String csv) {
-        return Arrays.asList(csv.split(","));
     }
 
     @Nullable
diff --git a/wikipedia/src/main/java/org/wikipedia/login/UserInfoStorage.java 
b/wikipedia/src/main/java/org/wikipedia/login/UserInfoStorage.java
index cce6937..960ce41 100644
--- a/wikipedia/src/main/java/org/wikipedia/login/UserInfoStorage.java
+++ b/wikipedia/src/main/java/org/wikipedia/login/UserInfoStorage.java
@@ -1,38 +1,27 @@
 package org.wikipedia.login;
 
-import android.content.SharedPreferences;
+import org.wikipedia.settings.Prefs;
 
 public class UserInfoStorage {
-    private static final String PREFERENCE_USERNAME = "username";
-    private static final String PREFERENCE_PASSWORD = "password";
-    private static final String PREFERENCE_USERID = "userID";
-
-    private final SharedPreferences prefs;
     private User currentUser;
-
-    public UserInfoStorage(SharedPreferences prefs) {
-        this.prefs = prefs;
-    }
 
     public boolean isLoggedIn() {
         return getUser() != null;
     }
 
     public void setUser(User user) {
-        prefs.edit()
-                .putString(PREFERENCE_USERNAME, user.getUsername())
-                .putString(PREFERENCE_PASSWORD, user.getPassword())
-                .putInt(PREFERENCE_USERID, user.getUserID())
-                .apply();
+        Prefs.setLoginUsername(user.getUsername());
+        Prefs.setLoginPassword(user.getPassword());
+        Prefs.setUserId(user.getUserID());
     }
 
     public User getUser() {
         if (currentUser == null) {
-            if (prefs.contains(PREFERENCE_USERNAME) && 
prefs.contains(PREFERENCE_PASSWORD)) {
+            if (Prefs.hasLoginUsername() && Prefs.hasLoginPassword()) {
                 currentUser = new User(
-                        prefs.getString(PREFERENCE_USERNAME, null),
-                        prefs.getString(PREFERENCE_PASSWORD, null),
-                        prefs.getInt(PREFERENCE_USERID, 0)
+                        Prefs.getLoginUsername(),
+                        Prefs.getLoginPassword(),
+                        Prefs.getLoginUserId()
                 );
             }
         }
@@ -41,11 +30,9 @@
     }
 
     public void clearUser() {
-        prefs.edit()
-                .remove(PREFERENCE_USERNAME)
-                .remove(PREFERENCE_PASSWORD)
-                .remove(PREFERENCE_USERID)
-                .apply();
+        Prefs.removeLoginUsername();
+        Prefs.removeLoginPassword();
+        Prefs.removeUserId();
         currentUser = null;
     }
 
diff --git a/wikipedia/src/main/java/org/wikipedia/nearby/NearbyFragment.java 
b/wikipedia/src/main/java/org/wikipedia/nearby/NearbyFragment.java
index 7acc87c..11ae2b3 100644
--- a/wikipedia/src/main/java/org/wikipedia/nearby/NearbyFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/nearby/NearbyFragment.java
@@ -639,7 +639,7 @@
                 viewHolder.markerButton.setVisibility(View.INVISIBLE);
             }
 
-            if (app.showImages()) {
+            if (app.isImageDownloadEnabled()) {
                 Picasso.with(getActivity())
                        .load(nearbyPage.getThumblUrl())
                        .placeholder(R.drawable.ic_pageimage_placeholder)
diff --git 
a/wikipedia/src/main/java/org/wikipedia/onboarding/OnboardingActivity.java 
b/wikipedia/src/main/java/org/wikipedia/onboarding/OnboardingActivity.java
index d1c7138..cebc142 100644
--- a/wikipedia/src/main/java/org/wikipedia/onboarding/OnboardingActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/onboarding/OnboardingActivity.java
@@ -2,9 +2,7 @@
 
 import android.app.Activity;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.os.Bundle;
-import android.preference.PreferenceManager;
 import android.support.annotation.NonNull;
 import android.text.Html;
 import android.view.View;
@@ -16,7 +14,7 @@
 import org.wikipedia.analytics.LoginFunnel;
 import org.wikipedia.analytics.OnboardingFunnel;
 import org.wikipedia.login.LoginActivity;
-import org.wikipedia.settings.PrefKeys;
+import org.wikipedia.settings.Prefs;
 import org.wikipedia.util.ActivityUtil;
 import org.wikipedia.util.L10nUtils;
 
@@ -106,16 +104,8 @@
      * Prepares the activity for finishing and ensuring onboarding is not 
shown again.
      */
     private void done() {
-        markAllAboard();
+        Prefs.setShowLoginEnabled(false);
         finish();
-    }
-
-    /**
-     * Adds a key to the SharedPreferences of the app to ensure that 
onboarding never shows again.
-     */
-    private void markAllAboard() {
-        SharedPreferences prefs = 
PreferenceManager.getDefaultSharedPreferences(this);
-        prefs.edit().putBoolean(PrefKeys.getOnboard(), true).apply();
     }
 
     @Override
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
index 37a0c0e..77220f8 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
@@ -20,7 +20,7 @@
 import org.wikipedia.recurring.RecurringTasksExecutor;
 import org.wikipedia.search.SearchArticlesFragment;
 import org.wikipedia.search.SearchBarHideHandler;
-import org.wikipedia.settings.PrefKeys;
+import org.wikipedia.settings.Prefs;
 import org.wikipedia.staticdata.MainPageNameData;
 import org.wikipedia.theme.ThemeChooserDialog;
 import org.wikipedia.util.ApiUtil;
@@ -46,6 +46,7 @@
 import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.app.ActionBarDrawerToggle;
 import android.support.v7.widget.Toolbar;
@@ -376,7 +377,7 @@
      */
     private boolean showOnboarding() {
         return (getIntent() == null || 
Intent.ACTION_MAIN.equals(getIntent().getAction()))
-                && 
!PreferenceManager.getDefaultSharedPreferences(this).getBoolean(PrefKeys.getOnboard(),
 false)
+                && Prefs.isShowLoginEnabled()
                 && !app.getUserInfoStorage().isLoggedIn();
     }
 
@@ -494,7 +495,7 @@
      * @param allowStateLoss Whether to allow state loss.
      */
     public void pushFragment(Fragment f, boolean allowStateLoss) {
-        drawerLayout.closeDrawer(Gravity.START);
+        drawerLayout.closeDrawer(GravityCompat.START);
         searchBarHideHandler.setForceNoFade(false);
         searchBarHideHandler.setFadeEnabled(false);
         // if the new fragment is the same class as the current topmost 
fragment,
@@ -560,8 +561,8 @@
         ACRA.getErrorReporter().putCustomData("api", 
title.getSite().getApiDomain());
         ACRA.getErrorReporter().putCustomData("title", title.toString());
 
-        if (drawerLayout.isDrawerOpen(Gravity.START)) {
-            drawerLayout.closeDrawer(Gravity.START);
+        if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
+            drawerLayout.closeDrawer(GravityCompat.START);
         }
         if (title.isSpecial()) {
             Utils.visitInExternalBrowser(this, 
Uri.parse(title.getMobileUri()));
@@ -622,8 +623,8 @@
             currentActionMode.finish();
             return;
         }
-        if (drawerLayout.isDrawerOpen(Gravity.START)) {
-            drawerLayout.closeDrawer(Gravity.START);
+        if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
+            drawerLayout.closeDrawer(GravityCompat.START);
             return;
         }
         if (searchFragment.onBackPressed()) {
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
index fff7b9d..9c87ea3 100755
--- a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
@@ -137,7 +137,7 @@
         super.onCreate(savedInstanceState);
         app = (WikipediaApp) getActivity().getApplicationContext();
         model = new PageViewModel();
-        if (Prefs.isUsingExperimentalPageLoad(app)) {
+        if (Prefs.isExperimentalPageLoadEnabled()) {
             pageLoadStrategy = new HtmlPageLoadStrategy();
         } else {
             pageLoadStrategy = new JsonPageLoadStrategy();
@@ -262,7 +262,7 @@
             }
         };
 
-        if (!Prefs.isUsingExperimentalPageLoad(app)) {
+        if (!Prefs.isExperimentalPageLoadEnabled()) {
             
bridge.injectStyleBundle(StyleBundle.getAvailableBundle(StyleBundle.BUNDLE_PAGEVIEW));
         }
 
diff --git a/wikipedia/src/main/java/org/wikipedia/page/SectionsFetchTask.java 
b/wikipedia/src/main/java/org/wikipedia/page/SectionsFetchTask.java
index 85a3fc1..7f49ad1 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/SectionsFetchTask.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/SectionsFetchTask.java
@@ -38,7 +38,7 @@
                 .param("sections", sectionsRequested)
                 .param("sectionprop", "toclevel|line|anchor")
                 .param("noheadings", "true");
-        if (!app.showImages()) {
+        if (!app.isImageDownloadEnabled()) {
             builder.param("noimages", "true");
         }
         return builder;
diff --git a/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java 
b/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
index 5ee19c3..c92194b 100755
--- a/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
@@ -7,12 +7,11 @@
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.analytics.ToCInteractionFunnel;
 import org.wikipedia.bridge.CommunicationBridge;
-import org.wikipedia.settings.PrefKeys;
+import org.wikipedia.settings.Prefs;
 import org.wikipedia.views.WikiDrawerLayout;
 import org.json.JSONException;
 import org.json.JSONObject;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.app.AppCompatActivity;
 import android.text.Html;
@@ -102,10 +101,8 @@
                 parentActivity.supportInvalidateOptionsMenu();
                 funnel.logOpen();
                 wasClicked = false;
-                final SharedPreferences prefs = 
PreferenceManager.getDefaultSharedPreferences(parentActivity);
-                final boolean knowsToC = 
prefs.getBoolean(PrefKeys.getKnowTocDrawer(), false);
-                if (!knowsToC) {
-                    showToCIntro(prefs, slidingPane);
+                if (Prefs.isTocTutorialEnabled()) {
+                    showToCIntro(slidingPane);
                 }
             }
 
@@ -135,9 +132,9 @@
         });
     }
 
-    private void showToCIntro(final SharedPreferences prefs, WikiDrawerLayout 
slidingPane) {
+    private void showToCIntro(WikiDrawerLayout slidingPane) {
         if (openedViaSwipe) {
-            knowSwipe(prefs);
+            knowSwipe();
         } else {
             final View gotItButton = 
slidingPane.findViewById(R.id.know_toc_drawer_button);
             if (!knowToCContainer.isShown()) {
@@ -151,14 +148,14 @@
             gotItButton.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    knowSwipe(prefs);
+                    knowSwipe();
                 }
             });
         }
     }
 
-    private void knowSwipe(SharedPreferences prefs) {
-        prefs.edit().putBoolean(PrefKeys.getKnowTocDrawer(), true).apply();
+    private void knowSwipe() {
+        Prefs.setTocTutorialEnabled(false);
         if (knowToCContainer.isShown()) {
             ViewAnimations.crossFade(knowToCContainer, tocList);
         }
@@ -217,12 +214,10 @@
         });
 
         if (!page.isMainPage() && !firstPage) {
-            final SharedPreferences prefs = 
PreferenceManager.getDefaultSharedPreferences(parentActivity);
-            final boolean knowsToC = 
prefs.getBoolean(PrefKeys.getKnowTocDrawer(), false);
-            if (!knowsToC) {
+            if (Prefs.isTocTutorialEnabled()) {
                 openedViaSwipe = false;
-                slidingPane.openDrawer(Gravity.END);
-                showToCIntro(prefs, slidingPane);
+                slidingPane.openDrawer(GravityCompat.END);
+                showToCIntro(slidingPane);
             }
         }
     }
@@ -230,16 +225,16 @@
     public void show() {
         if (slidingPane.getSlidingEnabled(Gravity.END)) {
             openedViaSwipe = false;
-            slidingPane.openDrawer(Gravity.END);
+            slidingPane.openDrawer(GravityCompat.END);
         }
     }
 
     public void hide() {
-        slidingPane.closeDrawer(Gravity.END);
+        slidingPane.closeDrawer(GravityCompat.END);
     }
 
     public boolean isVisible() {
-        return slidingPane.isDrawerOpen(Gravity.END);
+        return slidingPane.isDrawerOpen(GravityCompat.END);
     }
 
     public void setEnabled(boolean enabled) {
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
 
b/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
index 89a89ae..a12ff75 100644
--- 
a/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
@@ -386,7 +386,7 @@
 
             ImageView imageView = (ImageView) 
convertView.findViewById(R.id.result_image);
             String thumbnail = result.getThumbUrl();
-            if (!app.showImages() || thumbnail == null) {
+            if (!app.isImageDownloadEnabled() || thumbnail == null) {
                 Picasso.with(parent.getContext())
                         .load(R.drawable.ic_pageimage_placeholder)
                         .into(imageView);
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java 
b/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java
index bc88163..4e9200d 100755
--- 
a/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java
@@ -323,7 +323,7 @@
     public void beginLayout(OnLeadImageLayoutListener listener) {
         String thumbUrl = 
parentFragment.getPage().getPageProperties().getLeadImageUrl();
 
-        if (!WikipediaApp.getInstance().showImages() || displayHeight < 
MIN_SCREEN_HEIGHT_DP) {
+        if (!WikipediaApp.getInstance().isImageDownloadEnabled() || 
displayHeight < MIN_SCREEN_HEIGHT_DP) {
             // disable the lead image completely
             leadImagesEnabled = false;
         } else {
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
index 1287a58..1151673 100755
--- 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
@@ -254,7 +254,7 @@
                 }
             });
         }
-        if (!TextUtils.isEmpty(contents.getTitle().getThumbUrl()) && 
app.showImages()) {
+        if (!TextUtils.isEmpty(contents.getTitle().getThumbUrl()) && 
app.isImageDownloadEnabled()) {
             Picasso.with(getActivity())
                     .load(contents.getTitle().getThumbUrl())
                     .placeholder(layoutToggle == 1 ? 
Utils.getThemedAttributeId(getActivity(), R.attr.lead_image_drawable) : 
R.drawable.link_preview_gradient)
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewVersion.java
 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewVersion.java
index d953e35..61d0e94 100644
--- 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewVersion.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewVersion.java
@@ -19,7 +19,8 @@
     // Return results 0, 1, or 2.  For result of 3, also return 0 (no preview).
     // (For building one-off APKs for testing specific prototypes, hard-code 
version to 1 or 2.)
     public static int getVersion(WikipediaApp app) {
-        return ((app.getABTestingID() % LINK_PREVIEW_TOGGLE_WEIGHT) > 2) ? 0 : 
(app.getABTestingID() % LINK_PREVIEW_TOGGLE_WEIGHT);
+        int mod = app.getABTestingID() % LINK_PREVIEW_TOGGLE_WEIGHT;
+        return (mod > 2) ? 0 : mod;
     }
 
     private LinkPreviewVersion() {
diff --git 
a/wikipedia/src/main/java/org/wikipedia/savedpages/SavedPagesFragment.java 
b/wikipedia/src/main/java/org/wikipedia/savedpages/SavedPagesFragment.java
index b28bbd5..b9ad39a 100644
--- a/wikipedia/src/main/java/org/wikipedia/savedpages/SavedPagesFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/savedpages/SavedPagesFragment.java
@@ -16,8 +16,20 @@
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.util.SparseBooleanArray;
-import android.view.*;
-import android.widget.*;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
 import com.squareup.picasso.Picasso;
 
 import org.wikipedia.BackPressedHandler;
@@ -271,7 +283,7 @@
             title.setText(entry.getTitle().getDisplayText());
             view.setTag(entry);
 
-            if (app.showImages()) {
+            if (app.isImageDownloadEnabled()) {
                 Picasso.with(getActivity())
                        
.load(cursor.getString(SavedPageContentProvider.COL_INDEX_IMAGE))
                        .placeholder(R.drawable.ic_pageimage_placeholder)
diff --git 
a/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java 
b/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
index b1b91b1..aa1023a 100644
--- a/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
@@ -5,6 +5,7 @@
 import org.wikipedia.R;
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.page.PageActivity;
+
 import com.squareup.picasso.Picasso;
 import android.os.Bundle;
 import android.os.Handler;
@@ -421,7 +422,7 @@
             ImageView imageView = (ImageView) 
convertView.findViewById(R.id.result_image);
 
             String thumbnail = title.getThumbUrl();
-            if (app.showImages() && thumbnail != null) {
+            if (app.isImageDownloadEnabled() && thumbnail != null) {
                 Picasso.with(parent.getContext())
                         .load(thumbnail)
                         .placeholder(R.drawable.ic_pageimage_placeholder)
diff --git a/wikipedia/src/main/java/org/wikipedia/settings/PrefKeys.java 
b/wikipedia/src/main/java/org/wikipedia/settings/PrefKeys.java
deleted file mode 100644
index e80f2ff..0000000
--- a/wikipedia/src/main/java/org/wikipedia/settings/PrefKeys.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package org.wikipedia.settings;
-
-import android.content.res.Resources;
-import org.wikipedia.R;
-
-/** Keys in SharedPreference file used by this App. */
-public final class PrefKeys {
-    private static String PREFERENCE_CONTENT_LANGUAGE;
-    private static String PREFERENCE_COOKIE_DOMAINS;
-    private static String PREFERENCE_COOKIES_FOR_DOMAINS;
-    private static String PREFERENCE_EDITTOKEN_WIKIS;
-    private static String PREFERENCE_EDITTOKEN_FOR_WIKI;
-    private static String PREFERENCE_ZERO_INTERSTITIAL;
-    private static String PREFERENCE_REMOTE_CONFIG;
-    private static String PREFERENCE_EVENTLOGGING_ENABLED;
-    private static String PREFERENCE_STYLES_LAST_UPDATED;
-    private static String PREFERENCE_APP_INSTALL_ID;
-    private static String PREFERENCE_FEATURE_FLAG_ID;
-    private static String PREFERENCE_ONBOARD;
-    private static String PREFERENCE_TEXT_SIZE_MULTIPLIER;
-    private static String PREFERENCE_COLOR_THEME;
-    private static String PREFERENCE_CHANNEL;
-    private static String PREFERENCE_LANGUAGE_MRU;
-    private static String PREFERENCE_KNOW_TOC_DRAWER;
-    private static String PREFERENCE_SHOW_IMAGES;
-    private static String PREFERENCE_EXP_PAGE_LOAD;
-
-    private PrefKeys() { }
-
-    public static void initPreferenceKeys(Resources resources) {
-        PREFERENCE_CONTENT_LANGUAGE = 
resources.getString(R.string.preference_key_language);
-        PREFERENCE_COOKIE_DOMAINS = 
resources.getString(R.string.preference_cookie_domains);
-        PREFERENCE_COOKIES_FOR_DOMAINS = 
resources.getString(R.string.preference_cookies_for_domain);
-        PREFERENCE_EDITTOKEN_WIKIS = 
resources.getString(R.string.preference_edittoken_wikis);
-        PREFERENCE_EDITTOKEN_FOR_WIKI = 
resources.getString(R.string.preference_edittoken_for_wiki);
-        PREFERENCE_ZERO_INTERSTITIAL = 
resources.getString(R.string.preference_key_zero_interstitial);
-        PREFERENCE_REMOTE_CONFIG = 
resources.getString(R.string.preference_key_remote_config);
-        PREFERENCE_EVENTLOGGING_ENABLED = 
resources.getString(R.string.preference_key_eventlogging_opt_in);
-        PREFERENCE_STYLES_LAST_UPDATED = 
resources.getString(R.string.preference_key_styles_last_updated);
-        // The app install ID uses readingAppInstallID for backwards 
compatibility with analytics
-        PREFERENCE_APP_INSTALL_ID = 
resources.getString(R.string.preference_reading_app_install_id);
-        PREFERENCE_FEATURE_FLAG_ID = 
resources.getString(R.string.preference_feature_flag_id);
-        PREFERENCE_ONBOARD = resources.getString(R.string.preference_onboard);
-        PREFERENCE_TEXT_SIZE_MULTIPLIER = 
resources.getString(R.string.preference_text_size_multiplier);
-        PREFERENCE_COLOR_THEME = 
resources.getString(R.string.preference_color_theme);
-        PREFERENCE_CHANNEL = resources.getString(R.string.preference_channel);
-        PREFERENCE_LANGUAGE_MRU = 
resources.getString(R.string.preference_language_mru);
-        PREFERENCE_KNOW_TOC_DRAWER = 
resources.getString(R.string.preference_know_toc_drawer);
-        PREFERENCE_SHOW_IMAGES = 
resources.getString(R.string.preference_show_images);
-        PREFERENCE_EXP_PAGE_LOAD = 
resources.getString(R.string.preference_exp_page_load);
-    }
-
-    public static String getContentLanguageKey() {
-        return PREFERENCE_CONTENT_LANGUAGE;
-    }
-
-    public static String getCookieDomainsKey() {
-        return PREFERENCE_COOKIE_DOMAINS;
-    }
-
-    public static String getCookiesForDomain() {
-        return PREFERENCE_COOKIES_FOR_DOMAINS;
-    }
-
-    public static String getEditTokenWikis() {
-        return PREFERENCE_EDITTOKEN_WIKIS;
-    }
-
-    public static String getEditTokenForWiki() {
-        return PREFERENCE_EDITTOKEN_FOR_WIKI;
-    }
-
-    public static String getZeroInterstitial() {
-        return PREFERENCE_ZERO_INTERSTITIAL;
-    }
-
-    public static String getRemoteConfig() {
-        return PREFERENCE_REMOTE_CONFIG;
-    }
-
-    public static String getEventLoggingEnabled() {
-        return PREFERENCE_EVENTLOGGING_ENABLED;
-    }
-
-    public static String getStylesLastUpdated() {
-        return PREFERENCE_STYLES_LAST_UPDATED;
-    }
-
-    public static String getAppInstallID() {
-        return PREFERENCE_APP_INSTALL_ID;
-    }
-
-    public static String getFeatureFlagID() {
-        return PREFERENCE_FEATURE_FLAG_ID;
-    }
-
-    public static String getOnboard() {
-        return PREFERENCE_ONBOARD;
-    }
-
-    public static String getTextSizeMultiplier() {
-        return PREFERENCE_TEXT_SIZE_MULTIPLIER;
-    }
-
-    public static String getColorTheme() {
-        return PREFERENCE_COLOR_THEME;
-    }
-
-    public static String getChannel() {
-        return PREFERENCE_CHANNEL;
-    }
-
-    public static String getLanguageMru() {
-        return PREFERENCE_LANGUAGE_MRU;
-    }
-
-    public static String getKnowTocDrawer() {
-        return PREFERENCE_KNOW_TOC_DRAWER;
-    }
-
-    public static String getShowImages() {
-        return PREFERENCE_SHOW_IMAGES;
-    }
-
-    public static String getExperimentalPageLoad() {
-        return PREFERENCE_EXP_PAGE_LOAD;
-    }
-}
diff --git a/wikipedia/src/main/java/org/wikipedia/settings/PreferenceUtil.java 
b/wikipedia/src/main/java/org/wikipedia/settings/PreferenceUtil.java
deleted file mode 100644
index 4ec0825..0000000
--- a/wikipedia/src/main/java/org/wikipedia/settings/PreferenceUtil.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.wikipedia.settings;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-import android.support.annotation.Nullable;
-
-import org.wikipedia.WikipediaApp;
-
-public final class PreferenceUtil {
-    public static SharedPreferences getPreferences() {
-        return PreferenceManager.getDefaultSharedPreferences(getContext());
-    }
-
-    @Nullable
-    public static String getAppLanguageCode() {
-        return getString(PrefKeys.getContentLanguageKey(), null);
-    }
-
-    public static void setAppLanguageCode(String code) {
-        setString(PrefKeys.getContentLanguageKey(), code);
-    }
-
-    @Nullable
-    public static String getMruLanguageCodes() {
-        return getString(PrefKeys.getLanguageMru(), null);
-    }
-
-    public static void setMruLanguageCodes(String csv) {
-        setString(PrefKeys.getLanguageMru(), csv);
-    }
-
-    private static String getString(String key, String defaultValue) {
-        return getPreferences().getString(key, defaultValue);
-    }
-
-    private static void setString(String key, String value) {
-        getPreferences().edit().putString(key, value).apply();
-    }
-
-    private static Context getContext() {
-        return WikipediaApp.getInstance();
-    }
-
-    private PreferenceUtil() {
-    }
-}
\ No newline at end of file
diff --git a/wikipedia/src/main/java/org/wikipedia/settings/Prefs.java 
b/wikipedia/src/main/java/org/wikipedia/settings/Prefs.java
index 86c6621..93bbea1 100644
--- a/wikipedia/src/main/java/org/wikipedia/settings/Prefs.java
+++ b/wikipedia/src/main/java/org/wikipedia/settings/Prefs.java
@@ -1,23 +1,244 @@
 package org.wikipedia.settings;
 
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 
-/**
- * Setters and getters for share preferences.
- */
+import org.wikipedia.R;
+
+import static org.wikipedia.settings.PrefsIoUtil.contains;
+import static org.wikipedia.settings.PrefsIoUtil.getBoolean;
+import static org.wikipedia.settings.PrefsIoUtil.getInt;
+import static org.wikipedia.settings.PrefsIoUtil.getKey;
+import static org.wikipedia.settings.PrefsIoUtil.getString;
+import static org.wikipedia.settings.PrefsIoUtil.remove;
+import static org.wikipedia.settings.PrefsIoUtil.setBoolean;
+import static org.wikipedia.settings.PrefsIoUtil.setInt;
+import static org.wikipedia.settings.PrefsIoUtil.setString;
+
+/** Shared preferences utility for convenient POJO access. */
 public final class Prefs {
+    // Some keys are outdated or use inverted logic.
+
+    // null analysis + default check
+
+    @Nullable
+    public static String getAppChannel() {
+        return getString(R.string.preference_key_app_channel, "");
+    }
+
+    public static void setAppChannel(@Nullable String channel) {
+        setString(R.string.preference_key_app_channel, channel);
+    }
+
+    @NonNull
+    public static String getAppChannelKey() {
+        return getKey(R.string.preference_key_app_channel);
+    }
+
+    @Nullable
+    public static String getAppInstallId() {
+        return getString(R.string.preference_key_reading_app_install_id, null);
+    }
+
+    public static void setAppInstallId(@Nullable String id) {
+        // The app install ID uses readingAppInstallID for backwards 
compatibility with analytics.
+        setString(R.string.preference_key_reading_app_install_id, id);
+    }
+
+    @Nullable
+    public static String getAppLanguageCode() {
+        return getString(R.string.preference_key_language, null);
+    }
+
+    public static void setAppLanguageCode(@Nullable String code) {
+        setString(R.string.preference_key_language, code);
+    }
+
+    public static String getAppLanguageCodeKey() {
+        return getKey(R.string.preference_key_language);
+    }
+
+    public static int getColorThemeResourceId() {
+        return getInt(R.string.preference_key_color_theme, 
R.style.Theme_WikiLight);
+    }
+
+    public static void setColorThemeResourceId(int theme) {
+        // TODO: Is this safe? Are resource IDs guaranteed constant across app 
and tool versions?
+        setInt(R.string.preference_key_color_theme, theme);
+    }
+
+    @NonNull
+    public static String getCookieDomains() {
+        return getString(R.string.preference_key_cookie_domains, "");
+    }
+
+    public static void setCookieDomains(@Nullable String domains) {
+        setString(R.string.preference_key_cookie_domains, domains);
+    }
+
+    @NonNull
+    public static String getCookiesForDomain(@NonNull String domain) {
+        return getString(getCookiesForDomainKey(domain), "");
+    }
+
+    public static void setCookiesForDomain(@NonNull String domain, @Nullable 
String cookies) {
+        setString(getCookiesForDomainKey(domain), cookies);
+    }
+
+    public static void removeCookiesForDomain(@NonNull String domain) {
+        remove(getCookiesForDomainKey(domain));
+    }
+
+    @NonNull
+    public static String getEditTokenWikis() {
+        return getString(R.string.preference_key_edittoken_wikis, "");
+    }
+
+    public static void setEditTokenWikis(@Nullable String wikis) {
+        setString(R.string.preference_key_edittoken_wikis, wikis);
+    }
+
+    @Nullable
+    public static String getEditTokenForWiki(@NonNull String wiki) {
+        return getString(getEditTokenForWikiKey(wiki), null);
+    }
+
+    public static void setEditTokenForWiki(String wiki, String token) {
+        setString(getEditTokenForWikiKey(wiki), token);
+    }
+
+    public static void removeEditTokenForWiki(@NonNull String wiki) {
+        remove(getEditTokenForWikiKey(wiki));
+    }
+
+    public static int getFeatureFlagId() {
+        return getInt(R.string.preference_key_feature_flag_id, 0);
+    }
+
+    public static void setFeatureFlagId(int id) {
+        setInt(R.string.preference_key_feature_flag_id, id);
+    }
+
+    public static boolean hasFeatureFlagId() {
+        return contains(R.string.preference_key_feature_flag_id);
+    }
+
+    @Nullable
+    public static String getLoginUsername() {
+        return getString(R.string.preference_key_login_username, null);
+    }
+
+    public static void setLoginUsername(@Nullable String username) {
+        setString(R.string.preference_key_login_username, username);
+    }
+
+    public static boolean hasLoginUsername() {
+        return contains(R.string.preference_key_login_username);
+    }
+
+    public static void removeLoginUsername() {
+        remove(R.string.preference_key_login_username);
+    }
+
+    @Nullable
+    public static String getLoginPassword() {
+        return getString(R.string.preference_key_login_password, null);
+    }
+
+    public static void setLoginPassword(String password) {
+        setString(R.string.preference_key_login_password, password);
+    }
+
+    public static boolean hasLoginPassword() {
+        return contains(R.string.preference_key_login_password);
+    }
+
+    public static void removeLoginPassword() {
+        remove(R.string.preference_key_login_password);
+    }
+
+    public static int getLoginUserId() {
+        return getInt(R.string.preference_key_login_user_id, 0);
+    }
+
+    public static void setUserId(int id) {
+        setInt(R.string.preference_key_login_user_id, id);
+    }
+
+    public static void removeUserId() {
+        remove(R.string.preference_key_login_user_id);
+    }
+
+    @Nullable
+    public static String getMruLanguageCodeCsv() {
+        return getString(R.string.preference_key_language_mru, null);
+    }
+
+    public static void setMruLanguageCodeCsv(@Nullable String csv) {
+        setString(R.string.preference_key_language_mru, csv);
+    }
+
+    @NonNull
+    public static String getRemoteConfigJson() {
+        return getString(R.string.preference_key_remote_config, "{}");
+    }
+
+    public static void setRemoteConfigJson(@Nullable String json) {
+        setString(R.string.preference_key_remote_config, json);
+    }
+
+    public static int getTextSizeMultiplier() {
+        return getInt(R.string.preference_key_text_size_multiplier, 0);
+    }
+
+    public static void setTextSizeMultiplier(int multiplier) {
+        setInt(R.string.preference_key_text_size_multiplier, multiplier);
+    }
+
+    public static boolean isEventLoggingEnabled() {
+        return getBoolean(R.string.preference_key_eventlogging_opt_in, true);
+    }
+
+    public static boolean isExperimentalPageLoadEnabled() {
+        return getBoolean(R.string.preference_key_exp_page_load, false);
+    }
+
+    public static boolean isShowLoginEnabled() {
+        return !getBoolean(R.string.preference_key_onboard, true);
+    }
+
+    public static void setShowLoginEnabled(boolean enabled) {
+        setBoolean(R.string.preference_key_onboard, !enabled);
+    }
+
+    public static boolean isShowZeroInterstitialEnabled() {
+        return getBoolean(R.string.preference_key_zero_interstitial, true);
+    }
+
+    public static boolean isTocTutorialEnabled() {
+        return !getBoolean(R.string.preference_key_know_toc_drawer, true);
+    }
+
+    public static void setTocTutorialEnabled(boolean enabled) {
+        setBoolean(R.string.preference_key_know_toc_drawer, !enabled);
+    }
+
+    public static void setExperimentalPageLoadEnabled(boolean enabled) {
+        setBoolean(R.string.preference_key_exp_page_load, enabled);
+    }
+
+    public static boolean isImageDownloadEnabled() {
+        return getBoolean(R.string.preference_key_show_images, true);
+    }
+
+    private static String getCookiesForDomainKey(@NonNull String domain) {
+        return getKey(R.string.preference_key_cookies_for_domain_format, 
domain);
+    }
+
+    private static String getEditTokenForWikiKey(String wiki) {
+        return getKey(R.string.preference_key_edittoken_for_wiki_format, wiki);
+    }
+
     private Prefs() {
-    }
-
-    public static void setUsingExperimentalPageLoad(Context ctx, boolean 
newValue) {
-        SharedPreferences prefs = 
PreferenceManager.getDefaultSharedPreferences(ctx);
-        prefs.edit().putBoolean(PrefKeys.getExperimentalPageLoad(), 
newValue).apply();
-    }
-
-    public static boolean isUsingExperimentalPageLoad(Context ctx) {
-        SharedPreferences prefs = 
PreferenceManager.getDefaultSharedPreferences(ctx);
-        return prefs.getBoolean(PrefKeys.getExperimentalPageLoad(), false);
     }
 }
diff --git a/wikipedia/src/main/java/org/wikipedia/settings/PrefsIoUtil.java 
b/wikipedia/src/main/java/org/wikipedia/settings/PrefsIoUtil.java
new file mode 100644
index 0000000..7fee09b
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/settings/PrefsIoUtil.java
@@ -0,0 +1,109 @@
+package org.wikipedia.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.wikipedia.WikipediaApp;
+
+/** Shared preferences input / output utility providing set* functionality 
that writes to SP on the
+ * client's behalf, IO without client supplied {@link Context}, and wrappers 
for using string
+ * resources as keys, and unifies SP access. */
+/*package*/ final class PrefsIoUtil {
+    @Nullable
+    public static String getString(int keyResourceId, @Nullable String 
defaultValue) {
+        return getString(getKey(keyResourceId), defaultValue);
+    }
+
+    public static void setString(int keyResourceId, @Nullable String value) {
+        setString(getKey(keyResourceId), value);
+    }
+
+    public static int getInt(int keyResourceId, int defaultValue) {
+        return getInt(getKey(keyResourceId), defaultValue);
+    }
+
+    public static void setInt(int keyResourceId, int value) {
+        setInt(getKey(keyResourceId), value);
+    }
+
+    public static boolean getBoolean(int keyResourceId, boolean defaultValue) {
+        return getBoolean(getKey(keyResourceId), defaultValue);
+    }
+
+    public static void setBoolean(int keyResourceId, boolean value) {
+        setBoolean(getKey(keyResourceId), value);
+    }
+
+    @Nullable
+    public static String getString(String key, @Nullable String defaultValue) {
+        return getPreferences().getString(key, defaultValue);
+    }
+
+    public static void setString(String key, @Nullable String value) {
+        edit().putString(key, value).apply();
+    }
+
+    public static int getInt(String key, int defaultValue) {
+        return getPreferences().getInt(key, defaultValue);
+    }
+
+    public static void setInt(String key, int value) {
+        edit().putInt(key, value).apply();
+    }
+
+    public static boolean getBoolean(String key, boolean defaultValue) {
+        return getPreferences().getBoolean(key, defaultValue);
+    }
+
+    public static void setBoolean(String key, boolean value) {
+        edit().putBoolean(key, value).apply();
+    }
+
+    public static void remove(int keyResourceId) {
+        remove(getKey(keyResourceId));
+    }
+
+    public static void remove(String key) {
+        edit().remove(key).apply();
+    }
+
+    public static boolean contains(int keyResourceId) {
+        return getPreferences().contains(getKey(keyResourceId));
+    }
+
+    public static boolean contains(String key) {
+        return getPreferences().contains(key);
+    }
+
+    /** @return Key String resource from preference_keys.xml. */
+    @NonNull
+    public static String getKey(int id, Object... formatArgs) {
+        return getResources().getString(id, formatArgs);
+    }
+
+    @NonNull
+    private static SharedPreferences.Editor edit() {
+        return getPreferences().edit();
+    }
+
+    @NonNull
+    private static SharedPreferences getPreferences() {
+        return PreferenceManager.getDefaultSharedPreferences(getContext());
+    }
+
+    @NonNull
+    private static Resources getResources() {
+        return getContext().getResources();
+    }
+
+    @NonNull
+    private static Context getContext() {
+        return WikipediaApp.getInstance();
+    }
+
+    private PrefsIoUtil() { }
+}
\ No newline at end of file
diff --git 
a/wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java 
b/wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java
index 325d8d7..02e30f4 100644
--- a/wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java
+++ b/wikipedia/src/main/java/org/wikipedia/settings/SettingsActivityGB.java
@@ -87,8 +87,9 @@
 
     @Override
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, 
String key) {
-        if (key.equals(PrefKeys.getContentLanguageKey())) {
-            LanguagePreference pref = (LanguagePreference) 
findPreference(PrefKeys.getContentLanguageKey());
+        String languageKey = Prefs.getAppLanguageCodeKey();
+        if (key.equals(languageKey)) {
+            LanguagePreference pref = (LanguagePreference) 
findPreference(languageKey);
             
pref.setSummary(WikipediaApp.getInstance().getAppLanguageLocalizedName());
             setResult(SettingsActivity.ACTIVITY_RESULT_LANGUAGE_CHANGED);
         }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java 
b/wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java
index 9952cb4..b559ac0 100644
--- a/wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/settings/SettingsFragment.java
@@ -70,8 +70,9 @@
 
     @Override
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, 
String key) {
-        if (key.equals(PrefKeys.getContentLanguageKey())) {
-            LanguagePreference pref = (LanguagePreference) 
findPreference(PrefKeys.getContentLanguageKey());
+        String languageKey = Prefs.getAppLanguageCodeKey();
+        if (key.equals(languageKey)) {
+            LanguagePreference pref = (LanguagePreference) 
findPreference(languageKey);
             
pref.setSummary(WikipediaApp.getInstance().getAppLanguageLocalizedName());
             
getActivity().setResult(SettingsActivity.ACTIVITY_RESULT_LANGUAGE_CHANGED);
         }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/theme/ExperimentalPageLoadChooser.java 
b/wikipedia/src/main/java/org/wikipedia/theme/ExperimentalPageLoadChooser.java
index 325110c..fce929a 100644
--- 
a/wikipedia/src/main/java/org/wikipedia/theme/ExperimentalPageLoadChooser.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/theme/ExperimentalPageLoadChooser.java
@@ -18,11 +18,11 @@
     public static void initExperimentalPageLoadChooser(final Context context, 
View root) {
         LinearLayout layout = (LinearLayout) 
root.findViewById(R.id.experimental_page_load);
         CheckBox expPageLoadCB = (CheckBox) 
layout.findViewById(R.id.use_exp_page_load_cb);
-        expPageLoadCB.setChecked(Prefs.isUsingExperimentalPageLoad(context));
+        expPageLoadCB.setChecked(Prefs.isExperimentalPageLoadEnabled());
         expPageLoadCB.setOnCheckedChangeListener(new 
CompoundButton.OnCheckedChangeListener() {
             @Override
             public void onCheckedChanged(CompoundButton buttonView, boolean 
isChecked) {
-                Prefs.setUsingExperimentalPageLoad(context, isChecked);
+                Prefs.setExperimentalPageLoadEnabled(isChecked);
                 WikipediaApp.getInstance().getBus().post(new 
ThemeChangeEvent());
                 // Not ideal since it doesn't automatically reload the page
                 // but good enough for experimental switching.
diff --git 
a/wikipedia/src/main/java/org/wikipedia/theme/ThemeChooserDialog.java 
b/wikipedia/src/main/java/org/wikipedia/theme/ThemeChooserDialog.java
index da62bc0..ee42903 100644
--- a/wikipedia/src/main/java/org/wikipedia/theme/ThemeChooserDialog.java
+++ b/wikipedia/src/main/java/org/wikipedia/theme/ThemeChooserDialog.java
@@ -11,6 +11,7 @@
 import org.wikipedia.analytics.AppearanceChangeFunnel;
 import org.wikipedia.events.WebViewInvalidateEvent;
 import org.wikipedia.page.BottomDialog;
+import org.wikipedia.settings.Prefs;
 import org.wikipedia.util.ApiUtil;
 
 public class ThemeChooserDialog extends BottomDialog {
@@ -35,7 +36,7 @@
             public void onClick(View view) {
                 updatingFont = true;
                 float currentSize = app.getFontSize(getWindow());
-                app.setFontSizeMultiplier(app.getFontSizeMultiplier() - 1);
+                app.setFontSizeMultiplier(Prefs.getTextSizeMultiplier() - 1);
                 updateButtonState();
                 funnel.logFontSizeChange(currentSize, 
app.getFontSize(getWindow()));
             }
@@ -59,7 +60,7 @@
             public void onClick(View view) {
                 updatingFont = true;
                 float currentSize = app.getFontSize(getWindow());
-                app.setFontSizeMultiplier(app.getFontSizeMultiplier() + 1);
+                app.setFontSizeMultiplier(Prefs.getTextSizeMultiplier() + 1);
                 updateButtonState();
                 funnel.logFontSizeChange(currentSize, 
app.getFontSize(getWindow()));
             }
@@ -117,7 +118,7 @@
     }
 
     private void updateButtonState() {
-        int mult = app.getFontSizeMultiplier();
+        int mult = Prefs.getTextSizeMultiplier();
         if (updatingFont) {
             fontChangeProgressBar.setVisibility(View.VISIBLE);
             buttonDefaultTextSize.setEnabled(false);
diff --git a/wikipedia/src/main/java/org/wikipedia/util/StringUtil.java 
b/wikipedia/src/main/java/org/wikipedia/util/StringUtil.java
index 259011d..f9721d4 100644
--- a/wikipedia/src/main/java/org/wikipedia/util/StringUtil.java
+++ b/wikipedia/src/main/java/org/wikipedia/util/StringUtil.java
@@ -2,9 +2,15 @@
 
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import java.util.Arrays;
+import java.util.List;
 
 // TODO: Replace with Apache Commons Lang StringUtils.
 public final class StringUtil {
+    private static final String CSV_DELIMITER = ",";
+
     @NonNull
     public static String emptyIfNull(@Nullable String value) {
         return defaultIfNull(value, "");
@@ -26,5 +32,29 @@
         return value == null ? defaultValue : value;
     }
 
+    @NonNull
+    public static String listToCsv(@NonNull List<String> list) {
+        return TextUtils.join(CSV_DELIMITER, list);
+    }
+
+    @NonNull
+    public static String listToDelimitedString(@NonNull Iterable<String> list,
+                                               @NonNull String delimiter) {
+        return TextUtils.join(delimiter, list);
+    }
+
+    /** @return Nonnull immutable list. */
+    @NonNull
+    public static List<String> csvToList(@NonNull String csv) {
+        return delimiterStringToList(csv, CSV_DELIMITER);
+    }
+
+    /** @return Nonnull immutable list. */
+    @NonNull
+    public static List<String> delimiterStringToList(@NonNull String 
delimitedString,
+                                                     @NonNull String 
delimiter) {
+        return Arrays.asList(delimitedString.split(delimiter));
+    }
+
     private StringUtil() { }
 }
\ No newline at end of file

-- 
To view, visit https://gerrit.wikimedia.org/r/218815
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I5d2de61ae0adf163e6bbb39337236d1d8c592c84
Gerrit-PatchSet: 1
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Niedzielski <sniedziel...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to