diff options
Diffstat (limited to 'mobile/android/chrome/content/aboutHealthReport.js')
-rw-r--r-- | mobile/android/chrome/content/aboutHealthReport.js | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/mobile/android/chrome/content/aboutHealthReport.js b/mobile/android/chrome/content/aboutHealthReport.js new file mode 100644 index 000000000..070eb821d --- /dev/null +++ b/mobile/android/chrome/content/aboutHealthReport.js @@ -0,0 +1,192 @@ +// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +var { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Messaging.jsm"); +Cu.import("resource://gre/modules/SharedPreferences.jsm"); + +// Name of Android SharedPreference controlling whether to upload +// health reports. +const PREF_UPLOAD_ENABLED = "android.not_a_preference.healthreport.uploadEnabled"; + +// Name of Gecko Pref specifying report content location. +const PREF_REPORTURL = "datareporting.healthreport.about.reportUrl"; + +// Monotonically increasing wrapper API version number. +const WRAPPER_VERSION = 1; + +const EVENT_HEALTH_REQUEST = "HealthReport:Request"; +const EVENT_HEALTH_RESPONSE = "HealthReport:Response"; + +// about:healthreport prefs are stored in Firefox's default Android +// SharedPreferences. +var sharedPrefs = SharedPreferences.forApp(); + +var healthReportWrapper = { + init: function () { + let iframe = document.getElementById("remote-report"); + iframe.addEventListener("load", healthReportWrapper.initRemotePage, false); + let report = this._getReportURI(); + iframe.src = report.spec; + console.log("AboutHealthReport: loading content from " + report.spec); + + sharedPrefs.addObserver(PREF_UPLOAD_ENABLED, this, false); + Services.obs.addObserver(this, EVENT_HEALTH_RESPONSE, false); + }, + + observe: function (subject, topic, data) { + if (topic == PREF_UPLOAD_ENABLED) { + this.updatePrefState(); + } else if (topic == EVENT_HEALTH_RESPONSE) { + this.updatePayload(data); + } + }, + + uninit: function () { + sharedPrefs.removeObserver(PREF_UPLOAD_ENABLED, this); + Services.obs.removeObserver(this, EVENT_HEALTH_RESPONSE); + }, + + _getReportURI: function () { + let url = Services.urlFormatter.formatURLPref(PREF_REPORTURL); + // This handles URLs that already have query parameters. + let uri = Services.io.newURI(url, null, null).QueryInterface(Ci.nsIURL); + uri.query += ((uri.query != "") ? "&v=" : "v=") + WRAPPER_VERSION; + return uri; + }, + + onOptIn: function () { + console.log("AboutHealthReport: page sent opt-in command."); + sharedPrefs.setBoolPref(PREF_UPLOAD_ENABLED, true); + this.updatePrefState(); + }, + + onOptOut: function () { + console.log("AboutHealthReport: page sent opt-out command."); + sharedPrefs.setBoolPref(PREF_UPLOAD_ENABLED, false); + this.updatePrefState(); + }, + + updatePrefState: function () { + console.log("AboutHealthReport: sending pref state to page."); + try { + let prefs = { + enabled: sharedPrefs.getBoolPref(PREF_UPLOAD_ENABLED), + }; + this.injectData("prefs", prefs); + } catch (e) { + this.reportFailure(this.ERROR_PREFS_FAILED); + } + }, + + refreshPayload: function () { + console.log("AboutHealthReport: page requested fresh payload."); + Messaging.sendRequest({ + type: EVENT_HEALTH_REQUEST, + }); + }, + + updatePayload: function (data) { + healthReportWrapper.injectData("payload", data); + // Data is supposed to be a string, so the length should be + // defined. Just in case, we do this after injecting the data. + console.log("AboutHealthReport: sending payload to page " + + "(" + typeof(data) + " of length " + data.length + ")."); + }, + + injectData: function (type, content) { + let report = this._getReportURI(); + + // file: URIs can't be used for targetOrigin, so we use "*" for + // this special case. In all other cases, pass in the URL to the + // report so we properly restrict the message dispatch. + let reportUrl = (report.scheme == "file") ? "*" : report.spec; + + let data = { + type: type, + content: content, + }; + + let iframe = document.getElementById("remote-report"); + iframe.contentWindow.postMessage(data, reportUrl); + }, + + showSettings: function () { + console.log("AboutHealthReport: showing settings."); + Messaging.sendRequest({ + type: "Settings:Show", + resource: "preferences_vendor", + }); + }, + + launchUpdater: function () { + console.log("AboutHealthReport: launching updater."); + Messaging.sendRequest({ + type: "Updater:Launch", + }); + }, + + handleRemoteCommand: function (evt) { + switch (evt.detail.command) { + case "DisableDataSubmission": + this.onOptOut(); + break; + case "EnableDataSubmission": + this.onOptIn(); + break; + case "RequestCurrentPrefs": + this.updatePrefState(); + break; + case "RequestCurrentPayload": + this.refreshPayload(); + break; + case "ShowSettings": + this.showSettings(); + break; + case "LaunchUpdater": + this.launchUpdater(); + break; + default: + Cu.reportError("Unexpected remote command received: " + evt.detail.command + + ". Ignoring command."); + break; + } + }, + + initRemotePage: function () { + let iframe = document.getElementById("remote-report").contentDocument; + iframe.addEventListener("RemoteHealthReportCommand", + function onCommand(e) {healthReportWrapper.handleRemoteCommand(e);}, + false); + healthReportWrapper.injectData("begin", null); + }, + + // error handling + ERROR_INIT_FAILED: 1, + ERROR_PAYLOAD_FAILED: 2, + ERROR_PREFS_FAILED: 3, + + reportFailure: function (error) { + let details = { + errorType: error, + }; + healthReportWrapper.injectData("error", details); + }, + + handleInitFailure: function () { + healthReportWrapper.reportFailure(healthReportWrapper.ERROR_INIT_FAILED); + }, + + handlePayloadFailure: function () { + healthReportWrapper.reportFailure(healthReportWrapper.ERROR_PAYLOAD_FAILED); + }, +}; + +window.addEventListener("load", healthReportWrapper.init.bind(healthReportWrapper), false); +window.addEventListener("unload", healthReportWrapper.uninit.bind(healthReportWrapper), false); |