gecko/mobile/android/chrome/content/aboutHealthReport.js

194 lines
6.1 KiB
JavaScript

#filter substitution
// -*- 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";
const { 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.
let sharedPrefs = SharedPreferences.forApp();
let 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.");
sendMessageToJava({
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.");
sendMessageToJava({
type: "Settings:Show",
resource: "preferences_vendor",
});
},
launchUpdater: function () {
console.log("AboutHealthReport: launching updater.");
sendMessageToJava({
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);