1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/chrome/content/aboutHealthReport.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,193 @@ 1.4 +#filter substitution 1.5 +// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +"use strict"; 1.11 + 1.12 +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; 1.13 + 1.14 +Cu.import("resource://gre/modules/Services.jsm"); 1.15 +Cu.import("resource://gre/modules/Messaging.jsm"); 1.16 +Cu.import("resource://gre/modules/SharedPreferences.jsm"); 1.17 + 1.18 +// Name of Android SharedPreference controlling whether to upload 1.19 +// health reports. 1.20 +const PREF_UPLOAD_ENABLED = "android.not_a_preference.healthreport.uploadEnabled"; 1.21 + 1.22 +// Name of Gecko Pref specifying report content location. 1.23 +const PREF_REPORTURL = "datareporting.healthreport.about.reportUrl"; 1.24 + 1.25 +// Monotonically increasing wrapper API version number. 1.26 +const WRAPPER_VERSION = 1; 1.27 + 1.28 +const EVENT_HEALTH_REQUEST = "HealthReport:Request"; 1.29 +const EVENT_HEALTH_RESPONSE = "HealthReport:Response"; 1.30 + 1.31 +// about:healthreport prefs are stored in Firefox's default Android 1.32 +// SharedPreferences. 1.33 +let sharedPrefs = new SharedPreferences(); 1.34 + 1.35 +let healthReportWrapper = { 1.36 + init: function () { 1.37 + let iframe = document.getElementById("remote-report"); 1.38 + iframe.addEventListener("load", healthReportWrapper.initRemotePage, false); 1.39 + let report = this._getReportURI(); 1.40 + iframe.src = report.spec; 1.41 + console.log("AboutHealthReport: loading content from " + report.spec); 1.42 + 1.43 + sharedPrefs.addObserver(PREF_UPLOAD_ENABLED, this, false); 1.44 + Services.obs.addObserver(this, EVENT_HEALTH_RESPONSE, false); 1.45 + }, 1.46 + 1.47 + observe: function (subject, topic, data) { 1.48 + if (topic == PREF_UPLOAD_ENABLED) { 1.49 + this.updatePrefState(); 1.50 + } else if (topic == EVENT_HEALTH_RESPONSE) { 1.51 + this.updatePayload(data); 1.52 + } 1.53 + }, 1.54 + 1.55 + uninit: function () { 1.56 + sharedPrefs.removeObserver(PREF_UPLOAD_ENABLED, this); 1.57 + Services.obs.removeObserver(this, EVENT_HEALTH_RESPONSE); 1.58 + }, 1.59 + 1.60 + _getReportURI: function () { 1.61 + let url = Services.urlFormatter.formatURLPref(PREF_REPORTURL); 1.62 + // This handles URLs that already have query parameters. 1.63 + let uri = Services.io.newURI(url, null, null).QueryInterface(Ci.nsIURL); 1.64 + uri.query += ((uri.query != "") ? "&v=" : "v=") + WRAPPER_VERSION; 1.65 + return uri; 1.66 + }, 1.67 + 1.68 + onOptIn: function () { 1.69 + console.log("AboutHealthReport: page sent opt-in command."); 1.70 + sharedPrefs.setBoolPref(PREF_UPLOAD_ENABLED, true); 1.71 + this.updatePrefState(); 1.72 + }, 1.73 + 1.74 + onOptOut: function () { 1.75 + console.log("AboutHealthReport: page sent opt-out command."); 1.76 + sharedPrefs.setBoolPref(PREF_UPLOAD_ENABLED, false); 1.77 + this.updatePrefState(); 1.78 + }, 1.79 + 1.80 + updatePrefState: function () { 1.81 + console.log("AboutHealthReport: sending pref state to page."); 1.82 + try { 1.83 + let prefs = { 1.84 + enabled: sharedPrefs.getBoolPref(PREF_UPLOAD_ENABLED), 1.85 + }; 1.86 + this.injectData("prefs", prefs); 1.87 + } catch (e) { 1.88 + this.reportFailure(this.ERROR_PREFS_FAILED); 1.89 + } 1.90 + }, 1.91 + 1.92 + refreshPayload: function () { 1.93 + console.log("AboutHealthReport: page requested fresh payload."); 1.94 + sendMessageToJava({ 1.95 + type: EVENT_HEALTH_REQUEST, 1.96 + }); 1.97 + }, 1.98 + 1.99 + updatePayload: function (data) { 1.100 + healthReportWrapper.injectData("payload", data); 1.101 + // Data is supposed to be a string, so the length should be 1.102 + // defined. Just in case, we do this after injecting the data. 1.103 + console.log("AboutHealthReport: sending payload to page " + 1.104 + "(" + typeof(data) + " of length " + data.length + ")."); 1.105 + }, 1.106 + 1.107 + injectData: function (type, content) { 1.108 + let report = this._getReportURI(); 1.109 + 1.110 + // file: URIs can't be used for targetOrigin, so we use "*" for 1.111 + // this special case. In all other cases, pass in the URL to the 1.112 + // report so we properly restrict the message dispatch. 1.113 + let reportUrl = (report.scheme == "file") ? "*" : report.spec; 1.114 + 1.115 + let data = { 1.116 + type: type, 1.117 + content: content, 1.118 + }; 1.119 + 1.120 + let iframe = document.getElementById("remote-report"); 1.121 + iframe.contentWindow.postMessage(data, reportUrl); 1.122 + }, 1.123 + 1.124 + showSettings: function () { 1.125 + console.log("AboutHealthReport: showing settings."); 1.126 + sendMessageToJava({ 1.127 + type: "Settings:Show", 1.128 + resource: "preferences_vendor", 1.129 + }); 1.130 + }, 1.131 + 1.132 + launchUpdater: function () { 1.133 + console.log("AboutHealthReport: launching updater."); 1.134 + sendMessageToJava({ 1.135 + type: "Updater:Launch", 1.136 + }); 1.137 + }, 1.138 + 1.139 + handleRemoteCommand: function (evt) { 1.140 + switch (evt.detail.command) { 1.141 + case "DisableDataSubmission": 1.142 + this.onOptOut(); 1.143 + break; 1.144 + case "EnableDataSubmission": 1.145 + this.onOptIn(); 1.146 + break; 1.147 + case "RequestCurrentPrefs": 1.148 + this.updatePrefState(); 1.149 + break; 1.150 + case "RequestCurrentPayload": 1.151 + this.refreshPayload(); 1.152 + break; 1.153 + case "ShowSettings": 1.154 + this.showSettings(); 1.155 + break; 1.156 + case "LaunchUpdater": 1.157 + this.launchUpdater(); 1.158 + break; 1.159 + default: 1.160 + Cu.reportError("Unexpected remote command received: " + evt.detail.command + 1.161 + ". Ignoring command."); 1.162 + break; 1.163 + } 1.164 + }, 1.165 + 1.166 + initRemotePage: function () { 1.167 + let iframe = document.getElementById("remote-report").contentDocument; 1.168 + iframe.addEventListener("RemoteHealthReportCommand", 1.169 + function onCommand(e) {healthReportWrapper.handleRemoteCommand(e);}, 1.170 + false); 1.171 + healthReportWrapper.injectData("begin", null); 1.172 + }, 1.173 + 1.174 + // error handling 1.175 + ERROR_INIT_FAILED: 1, 1.176 + ERROR_PAYLOAD_FAILED: 2, 1.177 + ERROR_PREFS_FAILED: 3, 1.178 + 1.179 + reportFailure: function (error) { 1.180 + let details = { 1.181 + errorType: error, 1.182 + }; 1.183 + healthReportWrapper.injectData("error", details); 1.184 + }, 1.185 + 1.186 + handleInitFailure: function () { 1.187 + healthReportWrapper.reportFailure(healthReportWrapper.ERROR_INIT_FAILED); 1.188 + }, 1.189 + 1.190 + handlePayloadFailure: function () { 1.191 + healthReportWrapper.reportFailure(healthReportWrapper.ERROR_PAYLOAD_FAILED); 1.192 + }, 1.193 +}; 1.194 + 1.195 +window.addEventListener("load", healthReportWrapper.init.bind(healthReportWrapper), false); 1.196 +window.addEventListener("unload", healthReportWrapper.uninit.bind(healthReportWrapper), false); 1.197 \ No newline at end of file