Bug 1101006 - Refactor mozLoop.{get, set}LoopCharPref and mozLoop.{get, set}LoopBoolPref to mozLoop.{get, set}Pref that uses getPrefType. r=mikedeboer, a=lsblakk
authorJared Wein <jwein@mozilla.com>
Wed, 19 Nov 2014 13:29:27 -0500
changeset 226233 e44e811d520670841123222a0c27e5b928cc4d05
parent 226232 7ca685a7deb77161c37020b8df853e38595a55a8
child 226234 a41bd0a6c40cd7c72a48075c9d5927b3aa66b8c6
push id7300
push userryanvm@gmail.com
push dateMon, 24 Nov 2014 18:58:49 +0000
treeherdermozilla-aurora@6908b4d5326e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer, lsblakk
bugs1101006
milestone35.0a2
Bug 1101006 - Refactor mozLoop.{get, set}LoopCharPref and mozLoop.{get, set}LoopBoolPref to mozLoop.{get, set}Pref that uses getPrefType. r=mikedeboer, a=lsblakk
browser/components/loop/MozLoopAPI.jsm
browser/components/loop/MozLoopService.jsm
browser/components/loop/content/js/conversation.js
browser/components/loop/content/js/conversation.jsx
browser/components/loop/content/js/conversationViews.js
browser/components/loop/content/js/conversationViews.jsx
browser/components/loop/content/js/panel.js
browser/components/loop/content/js/panel.jsx
browser/components/loop/content/shared/js/activeRoomStore.js
browser/components/loop/content/shared/js/utils.js
browser/components/loop/standalone/content/js/standaloneMozLoop.js
browser/components/loop/test/desktop-local/client_test.js
browser/components/loop/test/desktop-local/conversationViews_test.js
browser/components/loop/test/desktop-local/conversation_test.js
browser/components/loop/test/desktop-local/panel_test.js
browser/components/loop/test/mochitest/browser_mozLoop_prefs.js
browser/components/loop/test/shared/activeRoomStore_test.js
browser/components/loop/test/shared/conversationStore_test.js
browser/components/loop/test/shared/utils_test.js
browser/components/loop/test/standalone/standaloneMozLoop_test.js
browser/components/loop/test/xpcshell/test_loopservice_loop_prefs.js
browser/components/loop/ui/fake-mozLoop.js
--- a/browser/components/loop/MozLoopAPI.jsm
+++ b/browser/components/loop/MozLoopAPI.jsm
@@ -409,88 +409,51 @@ function injectLoopAPI(targetWindow) {
       enumerable: true,
       writable: true,
       value: function(expiryTimeSeconds) {
         MozLoopService.noteCallUrlExpiry(expiryTimeSeconds);
       }
     },
 
     /**
-     * Set any character preference under "loop."
+     * Set any preference under "loop."
      *
      * @param {String} prefName The name of the pref without the preceding "loop."
-     * @param {String} stringValue The value to set.
+     * @param {*} value The value to set.
+     * @param {Enum} prefType Type of preference, defined at Ci.nsIPrefBranch. Optional.
      *
      * Any errors thrown by the Mozilla pref API are logged to the console
      * and cause false to be returned.
      */
-    setLoopCharPref: {
+    setLoopPref: {
       enumerable: true,
       writable: true,
-      value: function(prefName, value) {
-        MozLoopService.setLoopCharPref(prefName, value);
+      value: function(prefName, value, prefType) {
+        MozLoopService.setLoopPref(prefName, value, prefType);
       }
     },
 
     /**
-     * Return any preference under "loop." that's coercible to a character
-     * preference.
+     * Return any preference under "loop.".
      *
      * @param {String} prefName The name of the pref without the preceding
      * "loop."
+     * @param {Enum} prefType Type of preference, defined at Ci.nsIPrefBranch. Optional.
      *
      * Any errors thrown by the Mozilla pref API are logged to the console
      * and cause null to be returned. This includes the case of the preference
      * not being found.
      *
-     * @return {String} on success, null on error
+     * @return {*} on success, null on error
      */
-    getLoopCharPref: {
-      enumerable: true,
-      writable: true,
-      value: function(prefName) {
-        return MozLoopService.getLoopCharPref(prefName);
-      }
-    },
-
-    /**
-     * Set any boolean preference under "loop."
-     *
-     * @param {String} prefName The name of the pref without the preceding "loop."
-     * @param {bool} value The value to set.
-     *
-     * Any errors thrown by the Mozilla pref API are logged to the console
-     * and cause false to be returned.
-     */
-    setLoopBoolPref: {
+    getLoopPref: {
       enumerable: true,
       writable: true,
-      value: function(prefName, value) {
-        MozLoopService.setLoopBoolPref(prefName, value);
-      }
-    },
-
-    /**
-     * Return any preference under "loop." that's coercible to a boolean
-     * preference.
-     *
-     * @param {String} prefName The name of the pref without the preceding
-     * "loop."
-     *
-     * Any errors thrown by the Mozilla pref API are logged to the console
-     * and cause null to be returned. This includes the case of the preference
-     * not being found.
-     *
-     * @return {String} on success, null on error
-     */
-    getLoopBoolPref: {
-      enumerable: true,
-      writable: true,
-      value: function(prefName) {
-        return MozLoopService.getLoopBoolPref(prefName);
+      value: function(prefName, prefType) {
+        return MozLoopService.getLoopPref(prefName);
       }
     },
 
     /**
      * Starts alerting the user about an incoming call
      */
     startAlerting: {
       enumerable: true,
--- a/browser/components/loop/MozLoopService.jsm
+++ b/browser/components/loop/MozLoopService.jsm
@@ -1311,90 +1311,85 @@ this.MozLoopService = {
       return Services.prefs.getComplexValue("general.useragent.locale",
         Ci.nsISupportsString).data;
     } catch (ex) {
       return "en-US";
     }
   },
 
   /**
-   * Set any character preference under "loop.".
+   * Set any preference under "loop.".
    *
-   * @param {String} prefName The name of the pref without the preceding "loop."
-   * @param {String} value The value to set.
+   * @param {String} prefSuffix The name of the pref without the preceding "loop."
+   * @param {*} value The value to set.
+   * @param {Enum} prefType Type of preference, defined at Ci.nsIPrefBranch. Optional.
    *
    * Any errors thrown by the Mozilla pref API are logged to the console.
    */
-  setLoopCharPref: function(prefName, value) {
+  setLoopPref: function(prefSuffix, value, prefType) {
+    let prefName = "loop." + prefSuffix;
     try {
-      Services.prefs.setCharPref("loop." + prefName, value);
+      if (!prefType) {
+        prefType = Services.prefs.getPrefType(prefName);
+      }
+      switch (prefType) {
+        case Ci.nsIPrefBranch.PREF_STRING:
+          Services.prefs.setCharPref(prefName, value);
+          break;
+        case Ci.nsIPrefBranch.PREF_INT:
+          Services.prefs.setIntPref(prefName, value);
+          break;
+        case Ci.nsIPrefBranch.PREF_BOOL:
+          Services.prefs.setBoolPref(prefName, value);
+          break;
+        default:
+          log.error("invalid preference type setting " + prefName);
+          break;
+      }
     } catch (ex) {
-      log.error("setLoopCharPref had trouble setting " + prefName +
+      log.error("setLoopPref had trouble setting " + prefName +
         "; exception: " + ex);
     }
   },
 
   /**
-   * Return any preference under "loop." that's coercible to a character
-   * preference.
+   * Return any preference under "loop.".
    *
    * @param {String} prefName The name of the pref without the preceding
    * "loop."
+   * @param {Enum} prefType Type of preference, defined at Ci.nsIPrefBranch. Optional.
    *
    * Any errors thrown by the Mozilla pref API are logged to the console
    * and cause null to be returned. This includes the case of the preference
    * not being found.
    *
-   * @return {String} on success, null on error
+   * @return {*} on success, null on error
    */
-  getLoopCharPref: function(prefName) {
+  getLoopPref: function(prefSuffix, prefType) {
+    let prefName = "loop." + prefSuffix;
     try {
-      return Services.prefs.getCharPref("loop." + prefName);
-    } catch (ex) {
-      log.error("getLoopCharPref had trouble getting " + prefName +
-        "; exception: " + ex);
-      return null;
-    }
-  },
-
-  /**
-   * Set any boolean preference under "loop.".
-   *
-   * @param {String} prefName The name of the pref without the preceding "loop."
-   * @param {boolean} value The value to set.
-   *
-   * Any errors thrown by the Mozilla pref API are logged to the console.
-   */
-  setLoopBoolPref: function(prefName, value) {
-    try {
-      Services.prefs.setBoolPref("loop." + prefName, value);
+      if (!prefType) {
+        prefType = Services.prefs.getPrefType(prefName);
+      } else if (prefType != Services.prefs.getPrefType(prefName)) {
+        log.error("invalid type specified for preference");
+        return null;
+      }
+      switch (prefType) {
+        case Ci.nsIPrefBranch.PREF_STRING:
+          return Services.prefs.getCharPref(prefName);
+        case Ci.nsIPrefBranch.PREF_INT:
+          return Services.prefs.getIntPref(prefName);
+        case Ci.nsIPrefBranch.PREF_BOOL:
+          return Services.prefs.getBoolPref(prefName);
+        default:
+          log.error("invalid preference type getting " + prefName);
+          return null;
+      }
     } catch (ex) {
-      log.error("setLoopCharPref had trouble setting " + prefName +
-        "; exception: " + ex);
-    }
-  },
-
-  /**
-   * Return any preference under "loop." that's coercible to a character
-   * preference.
-   *
-   * @param {String} prefName The name of the pref without the preceding
-   * "loop."
-   *
-   * Any errors thrown by the Mozilla pref API are logged to the console
-   * and cause null to be returned. This includes the case of the preference
-   * not being found.
-   *
-   * @return {String} on success, null on error
-   */
-  getLoopBoolPref: function(prefName) {
-    try {
-      return Services.prefs.getBoolPref("loop." + prefName);
-    } catch (ex) {
-      log.error("getLoopBoolPref had trouble getting " + prefName +
+      log.error("getLoopPref had trouble getting " + prefName +
         "; exception: " + ex);
       return null;
     }
   },
 
   /**
    * Start the FxA login flow using the OAuth client and params from the Loop server.
    *
--- a/browser/components/loop/content/js/conversation.js
+++ b/browser/components/loop/content/js/conversation.js
@@ -293,23 +293,23 @@ loop.conversation = (function(mozL10n) {
           if (this.state.callFailed) {
             return GenericFailureView({
               cancelCall: this.closeWindow.bind(this)}
             );
           }
 
           document.title = mozL10n.get("conversation_has_ended");
 
-          var feebackAPIBaseUrl = navigator.mozLoop.getLoopCharPref(
+          var feebackAPIBaseUrl = navigator.mozLoop.getLoopPref(
             "feedback.baseUrl");
 
           var appVersionInfo = navigator.mozLoop.appVersionInfo;
 
           var feedbackClient = new loop.FeedbackAPIClient(feebackAPIBaseUrl, {
-            product: navigator.mozLoop.getLoopCharPref("feedback.product"),
+            product: navigator.mozLoop.getLoopPref("feedback.product"),
             platform: appVersionInfo.OS,
             channel: appVersionInfo.channel,
             version: appVersionInfo.version
           });
 
           return (
             sharedViews.FeedbackView({
               feedbackApiClient: feedbackClient, 
@@ -611,20 +611,20 @@ loop.conversation = (function(mozL10n) {
     // Do the initial L10n setup, we do this before anything
     // else to ensure the L10n environment is setup correctly.
     mozL10n.initialize(navigator.mozLoop);
 
     // Plug in an alternate client ID mechanism, as localStorage and cookies
     // don't work in the conversation window
     window.OT.overrideGuidStorage({
       get: function(callback) {
-        callback(null, navigator.mozLoop.getLoopCharPref("ot.guid"));
+        callback(null, navigator.mozLoop.getLoopPref("ot.guid"));
       },
       set: function(guid, callback) {
-        navigator.mozLoop.setLoopCharPref("ot.guid", guid);
+        navigator.mozLoop.setLoopPref("ot.guid", guid);
         callback(null);
       }
     });
 
     var dispatcher = new loop.Dispatcher();
     var client = new loop.Client();
     var sdkDriver = new loop.OTSdkDriver({
       dispatcher: dispatcher,
--- a/browser/components/loop/content/js/conversation.jsx
+++ b/browser/components/loop/content/js/conversation.jsx
@@ -293,23 +293,23 @@ loop.conversation = (function(mozL10n) {
           if (this.state.callFailed) {
             return <GenericFailureView
               cancelCall={this.closeWindow.bind(this)}
             />;
           }
 
           document.title = mozL10n.get("conversation_has_ended");
 
-          var feebackAPIBaseUrl = navigator.mozLoop.getLoopCharPref(
+          var feebackAPIBaseUrl = navigator.mozLoop.getLoopPref(
             "feedback.baseUrl");
 
           var appVersionInfo = navigator.mozLoop.appVersionInfo;
 
           var feedbackClient = new loop.FeedbackAPIClient(feebackAPIBaseUrl, {
-            product: navigator.mozLoop.getLoopCharPref("feedback.product"),
+            product: navigator.mozLoop.getLoopPref("feedback.product"),
             platform: appVersionInfo.OS,
             channel: appVersionInfo.channel,
             version: appVersionInfo.version
           });
 
           return (
             <sharedViews.FeedbackView
               feedbackApiClient={feedbackClient}
@@ -611,20 +611,20 @@ loop.conversation = (function(mozL10n) {
     // Do the initial L10n setup, we do this before anything
     // else to ensure the L10n environment is setup correctly.
     mozL10n.initialize(navigator.mozLoop);
 
     // Plug in an alternate client ID mechanism, as localStorage and cookies
     // don't work in the conversation window
     window.OT.overrideGuidStorage({
       get: function(callback) {
-        callback(null, navigator.mozLoop.getLoopCharPref("ot.guid"));
+        callback(null, navigator.mozLoop.getLoopPref("ot.guid"));
       },
       set: function(guid, callback) {
-        navigator.mozLoop.setLoopCharPref("ot.guid", guid);
+        navigator.mozLoop.setLoopPref("ot.guid", guid);
         callback(null);
       }
     });
 
     var dispatcher = new loop.Dispatcher();
     var client = new loop.Client();
     var sdkDriver = new loop.OTSdkDriver({
       dispatcher: dispatcher,
--- a/browser/components/loop/content/js/conversationViews.js
+++ b/browser/components/loop/content/js/conversationViews.js
@@ -458,23 +458,23 @@ loop.conversationViews = (function(mozL1
 
     /**
      * Used to setup and render the feedback view.
      */
     _renderFeedbackView: function() {
       document.title = mozL10n.get("conversation_has_ended");
 
       // XXX Bug 1076754 Feedback view should be redone in the Flux style.
-      var feebackAPIBaseUrl = navigator.mozLoop.getLoopCharPref(
+      var feebackAPIBaseUrl = navigator.mozLoop.getLoopPref(
         "feedback.baseUrl");
 
       var appVersionInfo = navigator.mozLoop.appVersionInfo;
 
       var feedbackClient = new loop.FeedbackAPIClient(feebackAPIBaseUrl, {
-        product: navigator.mozLoop.getLoopCharPref("feedback.product"),
+        product: navigator.mozLoop.getLoopPref("feedback.product"),
         platform: appVersionInfo.OS,
         channel: appVersionInfo.channel,
         version: appVersionInfo.version
       });
 
       return (
         sharedViews.FeedbackView({
           feedbackApiClient: feedbackClient, 
--- a/browser/components/loop/content/js/conversationViews.jsx
+++ b/browser/components/loop/content/js/conversationViews.jsx
@@ -458,23 +458,23 @@ loop.conversationViews = (function(mozL1
 
     /**
      * Used to setup and render the feedback view.
      */
     _renderFeedbackView: function() {
       document.title = mozL10n.get("conversation_has_ended");
 
       // XXX Bug 1076754 Feedback view should be redone in the Flux style.
-      var feebackAPIBaseUrl = navigator.mozLoop.getLoopCharPref(
+      var feebackAPIBaseUrl = navigator.mozLoop.getLoopPref(
         "feedback.baseUrl");
 
       var appVersionInfo = navigator.mozLoop.appVersionInfo;
 
       var feedbackClient = new loop.FeedbackAPIClient(feebackAPIBaseUrl, {
-        product: navigator.mozLoop.getLoopCharPref("feedback.product"),
+        product: navigator.mozLoop.getLoopPref("feedback.product"),
         platform: appVersionInfo.OS,
         channel: appVersionInfo.channel,
         version: appVersionInfo.version
       });
 
       return (
         <sharedViews.FeedbackView
           feedbackApiClient={feedbackClient}
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -35,17 +35,17 @@ loop.panel = (function(_, mozL10n) {
     },
 
     getInitialState: function() {
       // XXX Work around props.selectedTab being undefined initially.
       // When we don't need to rely on the pref, this can move back to
       // getDefaultProps (bug 1100258).
       return {
         selectedTab: this.props.selectedTab ||
-          (navigator.mozLoop.getLoopBoolPref("rooms.enabled") ?
+          (navigator.mozLoop.getLoopPref("rooms.enabled") ?
             "rooms" : "call")
       };
     },
 
     handleSelectTab: function(event) {
       var tabName = event.target.dataset.tabName;
       this.setState({selectedTab: tabName});
     },
@@ -161,25 +161,25 @@ loop.panel = (function(_, mozL10n) {
           )
         )
       );
     }
   });
 
   var GettingStartedView = React.createClass({displayName: 'GettingStartedView',
     componentDidMount: function() {
-      navigator.mozLoop.setLoopBoolPref("gettingStarted.seen", true);
+      navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
     },
 
     handleButtonClick: function() {
       navigator.mozLoop.openGettingStartedTour();
     },
 
     render: function() {
-      if (navigator.mozLoop.getLoopBoolPref("gettingStarted.seen")) {
+      if (navigator.mozLoop.getLoopPref("gettingStarted.seen")) {
         return null;
       }
       return (
         React.DOM.div({id: "fte-getstarted"}, 
           React.DOM.header({id: "fte-title"}, 
             mozL10n.get("first_time_experience_title", {
               "clientShortname": mozL10n.get("clientShortname2")
             })
@@ -189,24 +189,24 @@ loop.panel = (function(_, mozL10n) {
                   caption: mozL10n.get("first_time_experience_button_label")})
         )
       );
     }
   });
 
   var ToSView = React.createClass({displayName: 'ToSView',
     getInitialState: function() {
-      return {seenToS: navigator.mozLoop.getLoopCharPref('seenToS')};
+      return {seenToS: navigator.mozLoop.getLoopPref("seenToS")};
     },
 
     render: function() {
       if (this.state.seenToS == "unseen") {
         var locale = mozL10n.getLanguage();
-        var terms_of_use_url = navigator.mozLoop.getLoopCharPref('legal.ToS_url');
-        var privacy_notice_url = navigator.mozLoop.getLoopCharPref('legal.privacy_url');
+        var terms_of_use_url = navigator.mozLoop.getLoopPref('legal.ToS_url');
+        var privacy_notice_url = navigator.mozLoop.getLoopPref('legal.privacy_url');
         var tosHTML = mozL10n.get("legal_text_and_links3", {
           "clientShortname": mozL10n.get("clientShortname2"),
           "terms_of_use": React.renderComponentToStaticMarkup(
             React.DOM.a({href: terms_of_use_url, target: "_blank"}, 
               mozL10n.get("legal_text_tos")
             )
           ),
           "privacy_notice": React.renderComponentToStaticMarkup(
@@ -721,17 +721,17 @@ loop.panel = (function(_, mozL10n) {
           detailsButtonCallback: serviceError.error.friendlyDetailsButtonCallback,
         });
       } else {
         this.props.notifications.remove(this.props.notifications.get("service-error"));
       }
     },
 
     _roomsEnabled: function() {
-      return navigator.mozLoop.getLoopBoolPref("rooms.enabled");
+      return navigator.mozLoop.getLoopPref("rooms.enabled");
     },
 
     _onStatusChanged: function() {
       var profile = navigator.mozLoop.userProfile;
       var currUid = this.state.userProfile ? this.state.userProfile.uid : null;
       var newUid = profile ? profile.uid : null;
       if (currUid != newUid) {
         // On profile change (login, logout), switch back to the default tab.
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -35,17 +35,17 @@ loop.panel = (function(_, mozL10n) {
     },
 
     getInitialState: function() {
       // XXX Work around props.selectedTab being undefined initially.
       // When we don't need to rely on the pref, this can move back to
       // getDefaultProps (bug 1100258).
       return {
         selectedTab: this.props.selectedTab ||
-          (navigator.mozLoop.getLoopBoolPref("rooms.enabled") ?
+          (navigator.mozLoop.getLoopPref("rooms.enabled") ?
             "rooms" : "call")
       };
     },
 
     handleSelectTab: function(event) {
       var tabName = event.target.dataset.tabName;
       this.setState({selectedTab: tabName});
     },
@@ -161,25 +161,25 @@ loop.panel = (function(_, mozL10n) {
           </ul>
         </div>
       );
     }
   });
 
   var GettingStartedView = React.createClass({
     componentDidMount: function() {
-      navigator.mozLoop.setLoopBoolPref("gettingStarted.seen", true);
+      navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
     },
 
     handleButtonClick: function() {
       navigator.mozLoop.openGettingStartedTour();
     },
 
     render: function() {
-      if (navigator.mozLoop.getLoopBoolPref("gettingStarted.seen")) {
+      if (navigator.mozLoop.getLoopPref("gettingStarted.seen")) {
         return null;
       }
       return (
         <div id="fte-getstarted">
           <header id="fte-title">
             {mozL10n.get("first_time_experience_title", {
               "clientShortname": mozL10n.get("clientShortname2")
             })}
@@ -189,24 +189,24 @@ loop.panel = (function(_, mozL10n) {
                   caption={mozL10n.get("first_time_experience_button_label")} />
         </div>
       );
     }
   });
 
   var ToSView = React.createClass({
     getInitialState: function() {
-      return {seenToS: navigator.mozLoop.getLoopCharPref('seenToS')};
+      return {seenToS: navigator.mozLoop.getLoopPref("seenToS")};
     },
 
     render: function() {
       if (this.state.seenToS == "unseen") {
         var locale = mozL10n.getLanguage();
-        var terms_of_use_url = navigator.mozLoop.getLoopCharPref('legal.ToS_url');
-        var privacy_notice_url = navigator.mozLoop.getLoopCharPref('legal.privacy_url');
+        var terms_of_use_url = navigator.mozLoop.getLoopPref('legal.ToS_url');
+        var privacy_notice_url = navigator.mozLoop.getLoopPref('legal.privacy_url');
         var tosHTML = mozL10n.get("legal_text_and_links3", {
           "clientShortname": mozL10n.get("clientShortname2"),
           "terms_of_use": React.renderComponentToStaticMarkup(
             <a href={terms_of_use_url} target="_blank">
               {mozL10n.get("legal_text_tos")}
             </a>
           ),
           "privacy_notice": React.renderComponentToStaticMarkup(
@@ -721,17 +721,17 @@ loop.panel = (function(_, mozL10n) {
           detailsButtonCallback: serviceError.error.friendlyDetailsButtonCallback,
         });
       } else {
         this.props.notifications.remove(this.props.notifications.get("service-error"));
       }
     },
 
     _roomsEnabled: function() {
-      return navigator.mozLoop.getLoopBoolPref("rooms.enabled");
+      return navigator.mozLoop.getLoopPref("rooms.enabled");
     },
 
     _onStatusChanged: function() {
       var profile = navigator.mozLoop.userProfile;
       var currUid = this.state.userProfile ? this.state.userProfile.uid : null;
       var newUid = profile ? profile.uid : null;
       if (currUid != newUid) {
         // On profile change (login, logout), switch back to the default tab.
--- a/browser/components/loop/content/shared/js/activeRoomStore.js
+++ b/browser/components/loop/content/shared/js/activeRoomStore.js
@@ -333,17 +333,17 @@ loop.store.ActiveRoomStore = (function()
      * Handles recording when a remote peer has connected to the servers.
      */
     remotePeerConnected: function() {
       this.setStoreState({
         roomState: ROOM_STATES.HAS_PARTICIPANTS
       });
 
       // We've connected with a third-party, therefore stop displaying the ToS etc.
-      this._mozLoop.setLoopCharPref("seenToS", "seen");
+      this._mozLoop.setLoopPref("seenToS", "seen");
     },
 
     /**
      * Handles a remote peer disconnecting from the session.
      */
     remotePeerDisconnected: function() {
       // As we only support two users at the moment, we just set this
       // back to joined.
--- a/browser/components/loop/content/shared/js/utils.js
+++ b/browser/components/loop/content/shared/js/utils.js
@@ -43,17 +43,17 @@ loop.shared.utils = (function(mozL10n) {
    *
    * @param {String} prefName The name of the preference. Note that mozLoop adds
    *                          'loop.' to the start of the string.
    *
    * @return The value of the preference, or false if not available.
    */
   function getBoolPreference(prefName) {
     if (navigator.mozLoop) {
-      return !!navigator.mozLoop.getLoopBoolPref(prefName);
+      return !!navigator.mozLoop.getLoopPref(prefName);
     }
 
     return !!localStorage.getItem(prefName);
   }
 
   /**
    * Helper for general things
    */
@@ -105,17 +105,17 @@ loop.shared.utils = (function(mozL10n) {
     }
     navigator.mozLoop.composeEmail(
       mozL10n.get("share_email_subject4", {
         clientShortname: mozL10n.get("clientShortname2")
       }),
       mozL10n.get("share_email_body4", {
         callUrl: callUrl,
         clientShortname: mozL10n.get("clientShortname2"),
-        learnMoreUrl: navigator.mozLoop.getLoopCharPref("learnMoreUrl")
+        learnMoreUrl: navigator.mozLoop.getLoopPref("learnMoreUrl")
       }),
       recipient
     );
   }
 
   return {
     CALL_TYPES: CALL_TYPES,
     FAILURE_REASONS: FAILURE_REASONS,
--- a/browser/components/loop/standalone/content/js/standaloneMozLoop.js
+++ b/browser/components/loop/standalone/content/js/standaloneMozLoop.js
@@ -194,29 +194,29 @@ loop.StandaloneMozLoop = (function(mozL1
     /**
      * Stores a preference in the local storage for standalone.
      * Note: Some prefs are filtered out as they are not applicable
      * to the standalone UI.
      *
      * @param {String} prefName The name of the pref
      * @param {String} value The value to set.
      */
-    setLoopCharPref: function(prefName, value) {
+    setLoopPref: function(prefName, value) {
       if (prefName === "seenToS") {
         return;
       }
 
       localStorage.setItem(prefName, value);
     },
 
     /**
      * Gets a preference from the local storage for standalone.
      *
      * @param {String} prefName The name of the pref
      * @param {String} value The value to set.
      */
-    getLoopCharPref: function(prefName) {
+    getLoopPref: function(prefName) {
       return localStorage.getItem(prefName);
     }
   };
 
   return StandaloneMozLoop;
 })(navigator.mozL10n);
--- a/browser/components/loop/test/desktop-local/client_test.js
+++ b/browser/components/loop/test/desktop-local/client_test.js
@@ -23,17 +23,17 @@ describe("loop.Client", function() {
       message: "invalid token"
     };
 
   beforeEach(function() {
     sandbox = sinon.sandbox.create();
     callback = sinon.spy();
     fakeToken = "fakeTokenText";
     mozLoop = {
-      getLoopCharPref: sandbox.stub()
+      getLoopPref: sandbox.stub()
         .returns(null)
         .withArgs("hawk-session-token")
         .returns(fakeToken),
       ensureRegistered: sinon.stub().callsArgWith(1, null),
       noteCallUrlExpiry: sinon.spy(),
       hawkRequest: sinon.stub(),
       LOOP_SESSION_TYPE: {
         GUEST: 1,
--- a/browser/components/loop/test/desktop-local/conversationViews_test.js
+++ b/browser/components/loop/test/desktop-local/conversationViews_test.js
@@ -39,17 +39,17 @@ describe("loop.conversationViews", funct
           return "audio/ogg";
       },
       responseType: null,
       response: new ArrayBuffer(10),
       onload: null
     };
 
     navigator.mozLoop = {
-      getLoopCharPref: sinon.stub().returns("http://fakeurl"),
+      getLoopPref: sinon.stub().returns("http://fakeurl"),
       composeEmail: sinon.spy(),
       get appVersionInfo() {
         return {
           version: "42",
           channel: "test",
           platform: "test"
         };
       },
--- a/browser/components/loop/test/desktop-local/conversation_test.js
+++ b/browser/components/loop/test/desktop-local/conversation_test.js
@@ -33,19 +33,24 @@ describe("loop.conversation", function()
     navigator.mozLoop = {
       doNotDisturb: true,
       getStrings: function() {
         return JSON.stringify({textContent: "fakeText"});
       },
       get locale() {
         return "en-US";
       },
-      setLoopCharPref: sinon.stub(),
-      getLoopCharPref: sinon.stub().returns("http://fakeurl"),
-      getLoopBoolPref: sinon.stub(),
+      setLoopPref: sinon.stub(),
+      getLoopPref: function(prefName) {
+        if (prefName == "debug.sdk") {
+          return false;
+        }
+
+        return "http://fake";
+      },
       calls: {
         clearCallInProgress: sinon.stub()
       },
       LOOP_SESSION_TYPE: {
         GUEST: 1,
         FXA: 2
       },
       startAlerting: sinon.stub(),
@@ -641,17 +646,16 @@ describe("loop.conversation", function()
             return new Promise(function() {});
           },
           on: sandbox.spy()
         });
 
         icView = mountTestComponent();
 
         conversation.set("loopToken", "fakeToken");
-        navigator.mozLoop.getLoopCharPref.returns("http://fake");
         stubComponent(sharedView, "ConversationView");
       });
 
       describe("call:accepted", function() {
         it("should display the ConversationView",
           function() {
             conversation.accepted();
 
--- a/browser/components/loop/test/desktop-local/panel_test.js
+++ b/browser/components/loop/test/desktop-local/panel_test.js
@@ -29,20 +29,18 @@ describe("loop.panel", function() {
       doNotDisturb: true,
       fxAEnabled: true,
       getStrings: function() {
         return JSON.stringify({textContent: "fakeText"});
       },
       get locale() {
         return "en-US";
       },
-      setLoopCharPref: sandbox.stub(),
-      getLoopCharPref: sandbox.stub().returns("unseen"),
-      getLoopBoolPref: sandbox.stub(),
-      setLoopBoolPref: sandbox.stub(),
+      setLoopPref: sandbox.stub(),
+      getLoopPref: sandbox.stub().returns("unseen"),
       getPluralForm: function() {
         return "fakeText";
       },
       copyString: sandbox.stub(),
       noteCallUrlExpiry: sinon.spy(),
       composeEmail: sinon.spy(),
       telemetryAdd: sinon.spy(),
       contacts: {
@@ -171,17 +169,17 @@ describe("loop.panel", function() {
       }));
     }
 
     describe('TabView', function() {
       var view, callTab, roomsTab, contactsTab;
 
       describe("loop.rooms.enabled on", function() {
         beforeEach(function() {
-          navigator.mozLoop.getLoopBoolPref = function(pref) {
+          navigator.mozLoop.getLoopPref = function(pref) {
             if (pref === "rooms.enabled") {
               return true;
             }
           };
 
           view = createTestPanelView();
 
           [roomsTab, contactsTab] =
@@ -202,17 +200,17 @@ describe("loop.panel", function() {
 
           expect(roomsTab.getDOMNode().classList.contains("selected"))
             .to.be.true;
         });
       });
 
       describe("loop.rooms.enabled off", function() {
         beforeEach(function() {
-          navigator.mozLoop.getLoopBoolPref = function(pref) {
+          navigator.mozLoop.getLoopPref = function(pref) {
             if (pref === "rooms.enabled") {
               return false;
             }
           };
 
           view = createTestPanelView();
 
           [callTab, contactsTab] =
@@ -358,17 +356,17 @@ describe("loop.panel", function() {
     describe("#render", function() {
       it("should render a ToSView", function() {
         var view = createTestPanelView();
 
         TestUtils.findRenderedComponentWithType(view, loop.panel.ToSView);
       });
 
       it("should not render a ToSView when the view has been 'seen'", function() {
-        navigator.mozLoop.getLoopCharPref = function() {
+        navigator.mozLoop.getLoopPref = function() {
           return "seen";
         };
         var view = createTestPanelView();
 
         try {
           TestUtils.findRenderedComponentWithType(view, loop.panel.ToSView);
           sinon.assert.fail("Should not find the ToSView if it has been 'seen'");
         } catch (ex) {}
@@ -376,17 +374,17 @@ describe("loop.panel", function() {
 
       it("should render a GettingStarted view", function() {
         var view = createTestPanelView();
 
         TestUtils.findRenderedComponentWithType(view, loop.panel.GettingStartedView);
       });
 
       it("should not render a GettingStartedView when the view has been seen", function() {
-        navigator.mozLoop.getLoopBoolPref = function() {
+        navigator.mozLoop.getLoopPref = function() {
           return true;
         };
         var view = createTestPanelView();
 
         try {
           TestUtils.findRenderedComponentWithType(view, loop.panel.GettingStartedView);
           sinon.assert.fail("Should not find the GettingStartedView if it has been seen");
         } catch (ex) {}
@@ -858,17 +856,17 @@ describe("loop.panel", function() {
     it("should render when the value of loop.seenToS is not set", function() {
       var view = TestUtils.renderIntoDocument(loop.panel.ToSView());
 
       TestUtils.findRenderedDOMComponentWithClass(view, "terms-service");
     });
 
     it("should not render when the value of loop.seenToS is set to 'seen'",
       function(done) {
-        navigator.mozLoop.getLoopCharPref = function() {
+        navigator.mozLoop.getLoopPref = function() {
           return "seen";
         };
 
         try {
           TestUtils.findRenderedDOMComponentWithClass(view, "tos");
         } catch (err) {
           done();
         }
--- a/browser/components/loop/test/mochitest/browser_mozLoop_prefs.js
+++ b/browser/components/loop/test/mochitest/browser_mozLoop_prefs.js
@@ -10,31 +10,31 @@ add_task(loadLoopPanel);
 
 add_task(function* test_mozLoop_charPref() {
   registerCleanupFunction(function () {
     Services.prefs.clearUserPref("loop.test");
   });
 
   Assert.ok(gMozLoopAPI, "mozLoop should exist");
 
-  // Test setLoopCharPref
-  gMozLoopAPI.setLoopCharPref("test", "foo");
+  // Test setLoopPref
+  gMozLoopAPI.setLoopPref("test", "foo", Ci.nsIPrefBranch.PREF_STRING);
   Assert.equal(Services.prefs.getCharPref("loop.test"), "foo",
                "should set loop pref value correctly");
 
-  // Test getLoopCharPref
-  Assert.equal(gMozLoopAPI.getLoopCharPref("test"), "foo",
+  // Test getLoopPref
+  Assert.equal(gMozLoopAPI.getLoopPref("test"), "foo",
                "should get loop pref value correctly");
 });
 
 add_task(function* test_mozLoop_boolPref() {
   registerCleanupFunction(function () {
     Services.prefs.clearUserPref("loop.testBool");
   });
 
   Assert.ok(gMozLoopAPI, "mozLoop should exist");
 
   Services.prefs.setBoolPref("loop.testBool", true);
 
-  // Test getLoopCharPref
-  Assert.equal(gMozLoopAPI.getLoopBoolPref("testBool"), true,
+  // Test getLoopPref
+  Assert.equal(gMozLoopAPI.getLoopPref("testBool"), true,
                "should get loop pref value correctly");
 });
--- a/browser/components/loop/test/shared/activeRoomStore_test.js
+++ b/browser/components/loop/test/shared/activeRoomStore_test.js
@@ -15,17 +15,17 @@ describe("loop.store.ActiveRoomStore", f
   beforeEach(function() {
     sandbox = sinon.sandbox.create();
     sandbox.useFakeTimers();
 
     dispatcher = new loop.Dispatcher();
     sandbox.stub(dispatcher, "dispatch");
 
     fakeMozLoop = {
-      setLoopCharPref: sandbox.stub(),
+      setLoopPref: sandbox.stub(),
       rooms: {
         get: sinon.stub(),
         join: sinon.stub(),
         refreshMembership: sinon.stub(),
         leave: sinon.stub(),
         on: sinon.stub(),
         off: sinon.stub()
       }
@@ -517,18 +517,18 @@ describe("loop.store.ActiveRoomStore", f
       store.remotePeerConnected();
 
       expect(store.getStoreState().roomState).eql(ROOM_STATES.HAS_PARTICIPANTS);
     });
 
     it("should set the pref for ToS to `seen`", function() {
       store.remotePeerConnected();
 
-      sinon.assert.calledOnce(fakeMozLoop.setLoopCharPref);
-      sinon.assert.calledWithExactly(fakeMozLoop.setLoopCharPref,
+      sinon.assert.calledOnce(fakeMozLoop.setLoopPref);
+      sinon.assert.calledWithExactly(fakeMozLoop.setLoopPref,
         "seenToS", "seen");
     });
   });
 
   describe("#remotePeerDisconnected", function() {
     it("should set the state to `SESSION_CONNECTED`", function() {
       store.remotePeerDisconnected();
 
--- a/browser/components/loop/test/shared/conversationStore_test.js
+++ b/browser/components/loop/test/shared/conversationStore_test.js
@@ -32,17 +32,17 @@ describe("loop.store.ConversationStore",
       email: [{
         type: "home",
         value: "fakeEmail",
         pref: true
       }]
     };
 
     navigator.mozLoop = {
-      getLoopBoolPref: sandbox.stub(),
+      getLoopPref: sandbox.stub(),
       calls: {
         setCallInProgress: sandbox.stub(),
         clearCallInProgress: sandbox.stub()
       }
     };
 
     dispatcher = new loop.Dispatcher();
     client = {
--- a/browser/components/loop/test/shared/utils_test.js
+++ b/browser/components/loop/test/shared/utils_test.js
@@ -112,17 +112,17 @@ describe("loop.shared.utils", function()
   describe("#getBoolPreference", function() {
     afterEach(function() {
       localStorage.removeItem("test.true");
     });
 
     describe("mozLoop set", function() {
       beforeEach(function() {
         navigator.mozLoop = {
-          getLoopBoolPref: function(prefName) {
+          getLoopPref: function(prefName) {
             return prefName === "test.true";
           }
         };
       });
 
       it("should return the mozLoop preference", function() {
         expect(sharedUtils.getBoolPreference("test.true")).eql(true);
       });
@@ -151,17 +151,17 @@ describe("loop.shared.utils", function()
       sandbox.stub(navigator.mozL10n, "get", function(id) {
         switch(id) {
           case "share_email_subject4": return "subject";
           case "share_email_body4":    return "body";
         }
       });
       composeEmail = sandbox.spy();
       navigator.mozLoop = {
-        getLoopCharPref: sandbox.spy(),
+        getLoopPref: sandbox.spy(),
         composeEmail: composeEmail
       };
     });
 
     it("should compose a call url email", function() {
       sharedUtils.composeCallUrlEmail("http://invalid", "fake@invalid.tld");
 
       sinon.assert.calledOnce(composeEmail);
--- a/browser/components/loop/test/standalone/standaloneMozLoop_test.js
+++ b/browser/components/loop/test/standalone/standaloneMozLoop_test.js
@@ -41,43 +41,43 @@ describe("loop.StandaloneMozLoop", funct
   describe("#constructor", function() {
     it("should require a baseServerUrl setting", function() {
       expect(function() {
         new loop.StandaloneMozLoop();
       }).to.Throw(Error, /required/);
     });
   });
 
-  describe("#setLoopCharPref", function() {
+  describe("#setLoopPref", function() {
     afterEach(function() {
       localStorage.removeItem("fakePref");
     });
 
     it("should store the value of the preference", function() {
-      mozLoop.setLoopCharPref("fakePref", "fakeValue");
+      mozLoop.setLoopPref("fakePref", "fakeValue");
 
       expect(localStorage.getItem("fakePref")).eql("fakeValue");
     });
 
     it("should not store the value of seenToS", function() {
-      mozLoop.setLoopCharPref("seenToS", "fakeValue1");
+      mozLoop.setLoopPref("seenToS", "fakeValue1");
 
       expect(localStorage.getItem("seenToS")).eql(null);
     });
   });
 
-  describe("#getLoopCharPref", function() {
+  describe("#getLoopPref", function() {
     afterEach(function() {
       localStorage.removeItem("fakePref");
     });
 
     it("should return the value of the preference", function() {
       localStorage.setItem("fakePref", "fakeValue");
 
-      expect(mozLoop.getLoopCharPref("fakePref")).eql("fakeValue");
+      expect(mozLoop.getLoopPref("fakePref")).eql("fakeValue");
     });
   });
 
   describe("#rooms.join", function() {
     it("should POST to the server", function() {
       mozLoop.rooms.join("fakeToken", callback);
 
       expect(requests).to.have.length.of(1);
--- a/browser/components/loop/test/xpcshell/test_loopservice_loop_prefs.js
+++ b/browser/components/loop/test/xpcshell/test_loopservice_loop_prefs.js
@@ -1,108 +1,108 @@
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 /*global XPCOMUtils, Services, Assert */
 
 var fakeCharPrefName = "color";
 var fakeBoolPrefName = "boolean";
 var fakePrefValue = "green";
 
-function test_getLoopCharPref()
+function test_getLoopPref()
 {
   Services.prefs.setCharPref("loop." + fakeCharPrefName, fakePrefValue);
 
-  var returnedPref = MozLoopService.getLoopCharPref(fakeCharPrefName);
+  var returnedPref = MozLoopService.getLoopPref(fakeCharPrefName, Ci.nsIPrefBranch.PREF_STRING);
 
   Assert.equal(returnedPref, fakePrefValue,
     "Should return a char pref under the loop. branch");
   Services.prefs.clearUserPref("loop." + fakeCharPrefName);
 }
 
-function test_getLoopCharPref_not_found()
+function test_getLoopPref_not_found()
 {
-  var returnedPref = MozLoopService.getLoopCharPref(fakeCharPrefName);
+  var returnedPref = MozLoopService.getLoopPref(fakeCharPrefName);
 
   Assert.equal(returnedPref, null,
     "Should return null if a preference is not found");
 }
 
-function test_getLoopCharPref_non_coercible_type()
+function test_getLoopPref_non_coercible_type()
 {
   Services.prefs.setBoolPref("loop." + fakeCharPrefName, false);
 
-  var returnedPref = MozLoopService.getLoopCharPref(fakeCharPrefName);
+  var returnedPref = MozLoopService.getLoopPref(fakeCharPrefName, Ci.nsIPrefBranch.PREF_STRING);
 
   Assert.equal(returnedPref, null,
     "Should return null if the preference exists & is of a non-coercible type");
 }
 
-function test_setLoopCharPref()
+function test_setLoopPref()
 {
   Services.prefs.setCharPref("loop." + fakeCharPrefName, "red");
-  MozLoopService.setLoopCharPref(fakeCharPrefName, fakePrefValue);
+  MozLoopService.setLoopPref(fakeCharPrefName, fakePrefValue);
 
   var returnedPref = Services.prefs.getCharPref("loop." + fakeCharPrefName);
 
   Assert.equal(returnedPref, fakePrefValue,
     "Should set a char pref under the loop. branch");
   Services.prefs.clearUserPref("loop." + fakeCharPrefName);
 }
 
-function test_setLoopCharPref_new()
+function test_setLoopPref_new()
 {
   Services.prefs.clearUserPref("loop." + fakeCharPrefName);
-  MozLoopService.setLoopCharPref(fakeCharPrefName, fakePrefValue);
+  MozLoopService.setLoopPref(fakeCharPrefName, fakePrefValue, Ci.nsIPrefBranch.PREF_STRING);
 
   var returnedPref = Services.prefs.getCharPref("loop." + fakeCharPrefName);
 
   Assert.equal(returnedPref, fakePrefValue,
                "Should set a new char pref under the loop. branch");
   Services.prefs.clearUserPref("loop." + fakeCharPrefName);
 }
 
-function test_setLoopCharPref_non_coercible_type()
+function test_setLoopPref_non_coercible_type()
 {
-  MozLoopService.setLoopCharPref(fakeCharPrefName, true);
+  MozLoopService.setLoopPref(fakeCharPrefName, true);
 
   ok(true, "Setting non-coercible type should not fail");
 }
 
 
-function test_getLoopBoolPref()
+function test_getLoopPref_bool()
 {
   Services.prefs.setBoolPref("loop." + fakeBoolPrefName, true);
 
-  var returnedPref = MozLoopService.getLoopBoolPref(fakeBoolPrefName);
+  var returnedPref = MozLoopService.getLoopPref(fakeBoolPrefName);
 
   Assert.equal(returnedPref, true,
     "Should return a bool pref under the loop. branch");
   Services.prefs.clearUserPref("loop." + fakeBoolPrefName);
 }
 
-function test_getLoopBoolPref_not_found()
+function test_getLoopPref_not_found_bool()
 {
-  var returnedPref = MozLoopService.getLoopBoolPref(fakeBoolPrefName);
+  var returnedPref = MozLoopService.getLoopPref(fakeBoolPrefName);
 
   Assert.equal(returnedPref, null,
     "Should return null if a preference is not found");
 }
 
 
 function run_test()
 {
   setupFakeLoopServer();
 
-  test_getLoopCharPref();
-  test_getLoopCharPref_not_found();
-  test_getLoopCharPref_non_coercible_type();
-  test_setLoopCharPref();
-  test_setLoopCharPref_new();
-  test_setLoopCharPref_non_coercible_type();
+  test_getLoopPref();
+  test_getLoopPref_not_found();
+  test_getLoopPref_non_coercible_type();
+  test_setLoopPref();
+  test_setLoopPref_new();
+  test_setLoopPref_non_coercible_type();
 
-  test_getLoopBoolPref();
-  test_getLoopBoolPref_not_found();
+  test_getLoopPref_bool();
+  test_getLoopPref_not_found_bool();
 
   do_register_cleanup(function() {
     Services.prefs.clearUserPref("loop." + fakeCharPrefName);
     Services.prefs.clearUserPref("loop." + fakeBoolPrefName);
   });
 }
--- a/browser/components/loop/ui/fake-mozLoop.js
+++ b/browser/components/loop/ui/fake-mozLoop.js
@@ -44,18 +44,17 @@ var fakeRooms = [
 ];
 
 /**
  * Faking the mozLoop object which doesn't exist in regular web pages.
  * @type {Object}
  */
 navigator.mozLoop = {
   ensureRegistered: function() {},
-  getLoopCharPref: function() {},
-  getLoopBoolPref: function(pref) {
+  getLoopPref: function(pref) {
     // Ensure UI for rooms is displayed in the showcase.
     if (pref === "rooms.enabled") {
       return true;
     }
   },
   releaseCallData: function() {},
   copyString: function() {},
   contacts: {