Bug 784157 - Google Play Campaign Tracking: Better distribution pref handling, r=blassey r=bnicholson
authorMark Finkle <mfinkle@mozilla.com>
Fri, 05 Oct 2012 18:11:34 -0400
changeset 115776 2ba2e07e2fcd977b0bb81817fab467a2f1a34b9c
parent 115775 e09d7d9b5ed2477a951ce9800fe3df83f4b97ab7
child 115777 e0782e7cb92af522ac2f06417ed28a9e29ebd6fc
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblassey, bnicholson
bugs784157
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 784157 - Google Play Campaign Tracking: Better distribution pref handling, r=blassey r=bnicholson
mobile/android/base/ReferrerReceiver.java
mobile/android/chrome/content/browser.js
--- a/mobile/android/base/ReferrerReceiver.java
+++ b/mobile/android/base/ReferrerReceiver.java
@@ -42,30 +42,22 @@ public class ReferrerReceiver
             } catch (Exception e) {
             }
 
             String source = values.get("utm_source");
             String campaign = values.get("utm_campaign");
 
             if (source != null && UTM_SOURCE.equals(source) && campaign != null) {
                 try {
-                    JSONObject idPref = new JSONObject();
-                    idPref.put("name", "distribution.id");
-                    idPref.put("type", "string");
-                    idPref.put("value", "playstore");
-
-                    JSONObject versionPref = new JSONObject();
-                    versionPref.put("name", "distribution.version");
-                    versionPref.put("type", "string");
-                    versionPref.put("value", campaign);
+                    JSONObject data = new JSONObject();
+                    data.put("id", "playstore");
+                    data.put("version", campaign);
 
                     // Try to make sure the prefs are written as a group
-                    GeckoEvent idEvent = GeckoEvent.createBroadcastEvent("Preferences:Set", idPref.toString());
-                    GeckoAppShell.sendEventToGecko(idEvent);
-                    GeckoEvent versionEvent = GeckoEvent.createBroadcastEvent("Preferences:Set", versionPref.toString());
-                    GeckoAppShell.sendEventToGecko(versionEvent);
+                    GeckoEvent event = GeckoEvent.createBroadcastEvent("Distribution:Set", data.toString());
+                    GeckoAppShell.sendEventToGecko(event);
                 } catch (JSONException e) {
-                    Log.e(LOGTAG, "Error setting distribution prefs", e);
+                    Log.e(LOGTAG, "Error setting distribution", e);
                 }
             }
         }
     }
 }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -226,16 +226,17 @@ var BrowserApp = {
     CharacterEncoding.init();
     ActivityObserver.init();
     WebappsUI.init();
     RemoteDebugger.init();
     Reader.init();
     UserAgent.init();
     ExternalApps.init();
     MemoryObserver.init();
+    Distribution.init();
 #ifdef MOZ_TELEMETRY_REPORTING
     Telemetry.init();
 #endif
 #ifdef ACCESSIBILITY
     AccessFu.attach(window);
 #endif
 
     // Init LoginManager
@@ -526,16 +527,17 @@ var BrowserApp = {
     CharacterEncoding.uninit();
     SearchEngines.uninit();
     WebappsUI.uninit();
     RemoteDebugger.uninit();
     Reader.uninit();
     UserAgent.uninit();
     ExternalApps.uninit();
     MemoryObserver.uninit();
+    Distribution.uninit();
 #ifdef MOZ_TELEMETRY_REPORTING
     Telemetry.uninit();
 #endif
   },
 
   // This function returns false during periods where the browser displayed document is
   // different from the browser content document, so user actions and some kinds of viewport
   // updates should be ignored. This period starts when we start loading a new page or
@@ -7470,8 +7472,74 @@ var MemoryObserver = {
 
     let label = "[AboutMemoryDump|" + aLabel + "] ";
     dump(label + timestamp);
     for (let type in memory) {
       dump(label + type + " = " + memory[type]);
     }
   },
 };
+
+var Distribution = {
+  _file: null,
+
+  init: function dc_init() {
+    Services.obs.addObserver(this, "Distribution:Set", false);
+
+    // Look for file outside the APK:
+    // /data/data/org.mozilla.fennec/distribution.json
+    this._file = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
+    this._file.append("distribution.json");
+    if (this._file.exists()) {
+      let channel = NetUtil.newChannel(this._file);
+      channel.contentType = "application/json";
+      NetUtil.asyncFetch(channel, function(aStream, aResult) {
+        if (!Components.isSuccessCode(aResult)) {
+          Cu.reportError("Distribution: Could not read from distribution.json file");
+          return;
+        }
+
+        let raw = NetUtil.readInputStreamToString(aStream, aStream.available(), { charset : "UTF-8" }) || "";
+        aStream.close();
+
+        try {
+          this.update(JSON.parse(raw));
+        } catch (ex) {
+          Cu.reportError("Distribution: Could not parse JSON: " + ex);
+        }
+      }.bind(this));
+    } 
+  },
+
+  uninit: function dc_uninit() {
+    Services.obs.removeObserver(this, "Distribution:Set");
+  },
+
+  observe: function dc_observe(aSubject, aTopic, aData) {
+    if (aTopic == "Distribution:Set") {
+      // Update the prefs for this session
+      try {
+        this.update(JSON.parse(aData));
+      } catch (ex) {
+        Cu.reportError("Distribution: Could not parse JSON: " + ex);
+        return;
+      }
+
+      // Save the data for the later sessions
+      let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
+      ostream.init(this._file, 0x02 | 0x08 | 0x20, parseInt("600", 8), ostream.DEFER_OPEN);
+
+      let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
+      converter.charset = "UTF-8";
+
+      // Asynchronously copy the data to the file.
+      let istream = converter.convertToInputStream(aData);
+      NetUtil.asyncCopy(istream, ostream, function(rc) { });
+    }
+  },
+
+  update: function dc_update(aData) {
+    // Force the distribution preferences on the default branch
+    let defaults = Services.prefs.getDefaultBranch(null);
+    defaults.setCharPref("distribution.id", aData.id);
+    defaults.setCharPref("distribution.version", aData.version);
+  }
+};