Bug 1138503 - Add the default search engine to the Telemetry Environment. r=gfritzsche
authorAlessio Placitelli <alessio.placitelli@gmail.com>
Fri, 15 May 2015 02:12:00 -0400
changeset 244960 18c502f9c0746293dc15b82f3b334c313d10796a
parent 244959 2129ead20f6bf1cd91228e68bdd426e0add65c2a
child 244961 1f42548ebc0e5abc27b45a7ed508a31fce76b5a9
push id15721
push userryanvm@gmail.com
push dateThu, 21 May 2015 20:32:43 +0000
treeherderb2g-inbound@7ad1e1216ede [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgfritzsche
bugs1138503
milestone41.0a1
Bug 1138503 - Add the default search engine to the Telemetry Environment. r=gfritzsche
toolkit/components/telemetry/TelemetryEnvironment.jsm
toolkit/components/telemetry/docs/environment.rst
--- a/toolkit/components/telemetry/TelemetryEnvironment.jsm
+++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm
@@ -149,16 +149,18 @@ const PREF_APP_PARTNER_BRANCH = "app.par
 const PREF_PARTNER_ID = "mozilla.partner.id";
 const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
 const PREF_UPDATE_ENABLED = "app.update.enabled";
 const PREF_UPDATE_AUTODOWNLOAD = "app.update.auto";
 
 const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
 
 const EXPERIMENTS_CHANGED_TOPIC = "experiments-changed";
+const SEARCH_ENGINE_MODIFIED_TOPIC = "browser-search-engine-modified";
+const SEARCH_SERVICE_TOPIC = "browser-search-service";
 
 /**
  * Turn a millisecond timestamp into a day timestamp.
  *
  * @param aMsec a number of milliseconds since epoch.
  * @return the number of whole days denoted by the input.
  */
 function truncateToDays(aMsec) {
@@ -646,43 +648,45 @@ function EnvironmentCache() {
 
   this._currentEnvironment = {
     build: this._getBuild(),
     partner: this._getPartner(),
     system: this._getSystem(),
   };
 
   this._updateSettings();
+  // Fill in the default search engine, if the search provider is already initialized.
+  this._updateSearchEngine();
 
   // Build the remaining asynchronous parts of the environment. Don't register change listeners
   // until the initial environment has been built.
 
   this._addonBuilder = new EnvironmentAddonBuilder(this);
 
   let p = [ this._addonBuilder.init() ];
 #ifndef MOZ_WIDGET_ANDROID
   this._currentEnvironment.profile = {};
   p.push(this._updateProfile());
 #endif
 
+  let setup = () => {
+    this._initTask = null;
+    this._startWatchingPrefs();
+    this._addonBuilder.watchForChanges();
+    this._addObservers();
+    return this.currentEnvironment;
+  };
+
   this._initTask = Promise.all(p)
     .then(
-      () => {
-        this._initTask = null;
-        this._startWatchingPrefs();
-        this._addonBuilder.watchForChanges();
-        return this.currentEnvironment;
-      },
+      () => setup(),
       (err) => {
         // log errors but eat them for consumers
         this._log.error("EnvironmentCache - error while initializing", err);
-        this._initTask = null;
-        this._startWatchingPrefs();
-        this._addonBuilder.watchForChanges();
-        return this.currentEnvironment;
+        return setup();
       });
 }
 EnvironmentCache.prototype = {
   /**
    * The current environment data. The returned data is cloned to avoid
    * unexpected sharing or mutation.
    * @returns object
    */
@@ -794,16 +798,100 @@ EnvironmentCache.prototype = {
   _stopWatchingPrefs: function () {
     this._log.trace("_stopWatchingPrefs");
 
     for (let pref of this._watchedPrefs.keys()) {
       Preferences.ignore(pref, this._onPrefChanged, this);
     }
   },
 
+  _addObservers: function () {
+    // Watch the search engine change and service topics.
+    Services.obs.addObserver(this, SEARCH_ENGINE_MODIFIED_TOPIC, false);
+    Services.obs.addObserver(this, SEARCH_SERVICE_TOPIC, false);
+  },
+
+  _removeObservers: function () {
+    // Remove the search engine change and service observers.
+    Services.obs.removeObserver(this, SEARCH_ENGINE_MODIFIED_TOPIC);
+    Services.obs.removeObserver(this, SEARCH_SERVICE_TOPIC);
+  },
+
+  observe: function (aSubject, aTopic, aData) {
+    this._log.trace("observe - aTopic: " + aTopic + ", aData: " + aData);
+    switch (aTopic) {
+      case SEARCH_ENGINE_MODIFIED_TOPIC:
+        if (aData != "engine-default" && aData != "engine-current") {
+          return;
+        }
+        // Record the new default search choice and send the change notification.
+        this._onSearchEngineChange();
+        break;
+      case SEARCH_SERVICE_TOPIC:
+        if (aData != "init-complete") {
+          return;
+        }
+        // Now that the search engine init is complete, record the default search choice.
+        this._updateSearchEngine();
+        break;
+    }
+  },
+
+  /**
+   * Get the default search engine.
+   * @return {String} Returns the search engine identifier, "NONE" if no default search
+   *         engine is defined or "UNDEFINED" if no engine identifier or name can be found.
+   */
+  _getDefaultSearchEngine: function () {
+    let engine;
+    try {
+      engine = Services.search.defaultEngine;
+    } catch (e) {}
+
+    let name;
+    if (!engine) {
+      name = "NONE";
+    } else if (engine.identifier) {
+      name = engine.identifier;
+    } else if (engine.name) {
+      name = "other-" + engine.name;
+    } else {
+      name = "UNDEFINED";
+    }
+
+    return name;
+  },
+
+  /**
+   * Update the default search engine value.
+   */
+  _updateSearchEngine: function () {
+    this._log.trace("_updateSearchEngine - isInitialized: " + Services.search.isInitialized);
+    if (!Services.search.isInitialized) {
+      return;
+    }
+
+    // Make sure we have a settings section.
+    this._currentEnvironment.settings = this._currentEnvironment.settings || {};
+    // Update the search engine entry in the current environment.
+    this._currentEnvironment.settings.defaultSearchEngine = this._getDefaultSearchEngine();
+  },
+
+  /**
+   * Update the default search engine value and trigger the environment change.
+   */
+  _onSearchEngineChange: function () {
+    this._log.trace("_onSearchEngineChange");
+
+    // Finally trigger the environment change notification.
+    let oldEnvironment = Cu.cloneInto(this._currentEnvironment, myScope);
+    this._updateSearchEngine();
+    this._onEnvironmentChange("search-engine-changed", oldEnvironment);
+  },
+
   /**
    * Get the build data in object form.
    * @return Object containing the build data.
    */
   _getBuild: function () {
     let buildData = {
       applicationId: Services.appinfo.ID,
       applicationName: Services.appinfo.name,
--- a/toolkit/components/telemetry/docs/environment.rst
+++ b/toolkit/components/telemetry/docs/environment.rst
@@ -29,16 +29,17 @@ Structure::
         vendor: <string>, // e.g. "Mozilla"
         platformVersion: <string>, // e.g. "35.0"
         xpcomAbi: <string>, // e.g. "x86-msvc"
         hotfixVersion: <string>, // e.g. "20141211.01"
       },
       settings: {
         blocklistEnabled: <bool>, // true on failure
         isDefaultBrowser: <bool>, // null on failure, not available on Android
+        defaultSearchEngine: <string>, // e.g. "yahoo"
         e10sEnabled: <bool>, // false on failure
         telemetryEnabled: <bool>, // false on failure
         locale: <string>, // e.g. "it", null on failure
         update: {
           channel: <string>, // e.g. "release", null on failure
           enabled: <bool>, // true on failure
           autoDownload: <bool>, // true on failure
         },
@@ -184,8 +185,21 @@ Structure::
         ],
         activeExperiment: { // section is empty if there's no active experiment
             id: <string>, // id
             branch: <string>, // branch name
         },
         persona: <string>, // id of the current persona, null on GONK
       },
     }
+
+Settings
+--------
+
+defaultSearchEngine
+~~~~~~~~~~~~~~~~~~~
+Contains the string identifier or name of the default search engine provider. This will not be present in environment data collected before the Search Service initialization.
+
+The special value ``NONE`` could occur if there is no default search engine.
+
+The special value ``UNDEFINED`` could occur if a default search engine exists but its identifier could not be determined.
+
+This field's contents are ``Services.search.defaultEngine.identifier`` (if defined) or ``"other-"`` + ``Services.search.defaultEngine.name`` if not. In other words, search engines without an ``.identifier`` are prefixed with ``other-``.