1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/devtools/server/actors/device.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,234 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +const {Cc, Ci, Cu, CC} = require("chrome"); 1.9 +const Services = require("Services"); 1.10 +const protocol = require("devtools/server/protocol"); 1.11 +const {method, RetVal} = protocol; 1.12 +const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); 1.13 +const {LongStringActor} = require("devtools/server/actors/string"); 1.14 +const {DebuggerServer} = require("devtools/server/main"); 1.15 + 1.16 +Cu.import("resource://gre/modules/PermissionsTable.jsm") 1.17 + 1.18 +const APP_MAP = { 1.19 + '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'firefox', 1.20 + '{3550f703-e582-4d05-9a08-453d09bdfdc6}': 'thunderbird', 1.21 + '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}': 'seamonkey', 1.22 + '{718e30fb-e89b-41dd-9da7-e25a45638b28}': 'sunbird', 1.23 + '{3c2e2abc-06d4-11e1-ac3b-374f68613e61}': 'b2g', 1.24 + '{aa3c5121-dab2-40e2-81ca-7ea25febc110}': 'mobile/android', 1.25 + '{a23983c0-fd0e-11dc-95ff-0800200c9a66}': 'mobile/xul' 1.26 +} 1.27 + 1.28 +exports.register = function(handle) { 1.29 + handle.addGlobalActor(DeviceActor, "deviceActor"); 1.30 +}; 1.31 + 1.32 +exports.unregister = function(handle) { 1.33 +}; 1.34 + 1.35 +let DeviceActor = protocol.ActorClass({ 1.36 + typeName: "device", 1.37 + 1.38 + _desc: null, 1.39 + 1.40 + _getAppIniString : function(section, key) { 1.41 + let inifile = Services.dirsvc.get("GreD", Ci.nsIFile); 1.42 + inifile.append("application.ini"); 1.43 + 1.44 + if (!inifile.exists()) { 1.45 + inifile = Services.dirsvc.get("CurProcD", Ci.nsIFile); 1.46 + inifile.append("application.ini"); 1.47 + } 1.48 + 1.49 + if (!inifile.exists()) { 1.50 + return undefined; 1.51 + } 1.52 + 1.53 + let iniParser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].getService(Ci.nsIINIParserFactory).createINIParser(inifile); 1.54 + try { 1.55 + return iniParser.getString(section, key); 1.56 + } catch (e) { 1.57 + return undefined; 1.58 + } 1.59 + }, 1.60 + 1.61 + _getSetting: function(name) { 1.62 + let deferred = promise.defer(); 1.63 + 1.64 + if ("@mozilla.org/settingsService;1" in Cc) { 1.65 + let settingsService = Cc["@mozilla.org/settingsService;1"].getService(Ci.nsISettingsService); 1.66 + let req = settingsService.createLock().get(name, { 1.67 + handle: (name, value) => deferred.resolve(value), 1.68 + handleError: (error) => deferred.reject(error), 1.69 + }); 1.70 + } else { 1.71 + deferred.reject(new Error("No settings service")); 1.72 + } 1.73 + return deferred.promise; 1.74 + }, 1.75 + 1.76 + getDescription: method(function() { 1.77 + // Most of this code is inspired from Nightly Tester Tools: 1.78 + // https://wiki.mozilla.org/Auto-tools/Projects/NightlyTesterTools 1.79 + 1.80 + let appInfo = Services.appinfo; 1.81 + let win = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType); 1.82 + let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); 1.83 + 1.84 + desc = { 1.85 + appid: appInfo.ID, 1.86 + apptype: APP_MAP[appInfo.ID], 1.87 + vendor: appInfo.vendor, 1.88 + name: appInfo.name, 1.89 + version: appInfo.version, 1.90 + appbuildid: appInfo.appBuildID, 1.91 + platformbuildid: appInfo.platformBuildID, 1.92 + platformversion: appInfo.platformVersion, 1.93 + geckobuildid: appInfo.platformBuildID, 1.94 + geckoversion: appInfo.platformVersion, 1.95 + changeset: this._getAppIniString("App", "SourceStamp"), 1.96 + useragent: win.navigator.userAgent, 1.97 + locale: Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry).getSelectedLocale("global"), 1.98 + os: null, 1.99 + hardware: "unknown", 1.100 + processor: appInfo.XPCOMABI.split("-")[0], 1.101 + compiler: appInfo.XPCOMABI.split("-")[1], 1.102 + dpi: utils.displayDPI, 1.103 + brandName: null, 1.104 + channel: null, 1.105 + profile: null, 1.106 + width: win.screen.width, 1.107 + height: win.screen.height 1.108 + }; 1.109 + 1.110 + // Profile 1.111 + let profd = Services.dirsvc.get("ProfD", Ci.nsILocalFile); 1.112 + let profservice = Cc["@mozilla.org/toolkit/profile-service;1"].getService(Ci.nsIToolkitProfileService); 1.113 + var profiles = profservice.profiles; 1.114 + while (profiles.hasMoreElements()) { 1.115 + let profile = profiles.getNext().QueryInterface(Ci.nsIToolkitProfile); 1.116 + if (profile.rootDir.path == profd.path) { 1.117 + desc.profile = profile.name; 1.118 + break; 1.119 + } 1.120 + } 1.121 + 1.122 + if (!desc.profile) { 1.123 + desc.profile = profd.leafName; 1.124 + } 1.125 + 1.126 + // Channel 1.127 + try { 1.128 + desc.channel = Services.prefs.getCharPref('app.update.channel'); 1.129 + } catch(e) {} 1.130 + 1.131 + if (desc.apptype == "b2g") { 1.132 + // B2G specific 1.133 + desc.os = "B2G"; 1.134 + 1.135 + return this._getSetting('deviceinfo.hardware') 1.136 + .then(value => desc.hardware = value) 1.137 + .then(() => this._getSetting('deviceinfo.os')) 1.138 + .then(value => desc.version = value) 1.139 + .then(() => desc); 1.140 + } 1.141 + 1.142 + // Not B2G 1.143 + desc.os = appInfo.OS; 1.144 + let bundle = Services.strings.createBundle("chrome://branding/locale/brand.properties"); 1.145 + if (bundle) { 1.146 + desc.brandName = bundle.GetStringFromName("brandFullName"); 1.147 + } 1.148 + 1.149 + return desc; 1.150 + 1.151 + }, {request: {},response: { value: RetVal("json")}}), 1.152 + 1.153 + getWallpaper: method(function() { 1.154 + let deferred = promise.defer(); 1.155 + this._getSetting("wallpaper.image").then((blob) => { 1.156 + let FileReader = CC("@mozilla.org/files/filereader;1"); 1.157 + let reader = new FileReader(); 1.158 + let conn = this.conn; 1.159 + reader.addEventListener("load", function() { 1.160 + let str = new LongStringActor(conn, reader.result); 1.161 + deferred.resolve(str); 1.162 + }); 1.163 + reader.addEventListener("error", function() { 1.164 + deferred.reject(reader.error); 1.165 + }); 1.166 + reader.readAsDataURL(blob); 1.167 + }); 1.168 + return deferred.promise; 1.169 + }, {request: {},response: { value: RetVal("longstring")}}), 1.170 + 1.171 + screenshotToDataURL: method(function() { 1.172 + let window = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType); 1.173 + let canvas = window.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); 1.174 + let width = window.innerWidth; 1.175 + let height = window.innerHeight; 1.176 + canvas.setAttribute('width', width); 1.177 + canvas.setAttribute('height', height); 1.178 + let context = canvas.getContext('2d'); 1.179 + let flags = 1.180 + context.DRAWWINDOW_DRAW_CARET | 1.181 + context.DRAWWINDOW_DRAW_VIEW | 1.182 + context.DRAWWINDOW_USE_WIDGET_LAYERS; 1.183 + context.drawWindow(window, 0, 0, width, height, 'rgb(255,255,255)', flags); 1.184 + let dataURL = canvas.toDataURL('image/png') 1.185 + return new LongStringActor(this.conn, dataURL); 1.186 + }, {request: {},response: { value: RetVal("longstring")}}), 1.187 + 1.188 + getRawPermissionsTable: method(function() { 1.189 + return { 1.190 + rawPermissionsTable: PermissionsTable, 1.191 + UNKNOWN_ACTION: Ci.nsIPermissionManager.UNKNOWN_ACTION, 1.192 + ALLOW_ACTION: Ci.nsIPermissionManager.ALLOW_ACTION, 1.193 + DENY_ACTION: Ci.nsIPermissionManager.DENY_ACTION, 1.194 + PROMPT_ACTION: Ci.nsIPermissionManager.PROMPT_ACTION 1.195 + }; 1.196 + }, {request: {},response: { value: RetVal("json")}}) 1.197 +}); 1.198 + 1.199 +let DeviceFront = protocol.FrontClass(DeviceActor, { 1.200 + initialize: function(client, form) { 1.201 + protocol.Front.prototype.initialize.call(this, client); 1.202 + this.actorID = form.deviceActor; 1.203 + client.addActorPool(this); 1.204 + this.manage(this); 1.205 + }, 1.206 + 1.207 + screenshotToBlob: function() { 1.208 + return this.screenshotToDataURL().then(longstr => { 1.209 + return longstr.string().then(dataURL => { 1.210 + let deferred = promise.defer(); 1.211 + longstr.release().then(null, Cu.reportError); 1.212 + let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); 1.213 + req.open("GET", dataURL, true); 1.214 + req.responseType = "blob"; 1.215 + req.onload = () => { 1.216 + deferred.resolve(req.response); 1.217 + }; 1.218 + req.onerror = () => { 1.219 + deferred.reject(req.status); 1.220 + } 1.221 + req.send(); 1.222 + return deferred.promise; 1.223 + }); 1.224 + }); 1.225 + }, 1.226 +}); 1.227 + 1.228 +const _knownDeviceFronts = new WeakMap(); 1.229 + 1.230 +exports.getDeviceFront = function(client, form) { 1.231 + if (_knownDeviceFronts.has(client)) 1.232 + return _knownDeviceFronts.get(client); 1.233 + 1.234 + let front = new DeviceFront(client, form); 1.235 + _knownDeviceFronts.set(client, front); 1.236 + return front; 1.237 +}