Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const {Cc, Ci, Cu, CC} = require("chrome");
6 const Services = require("Services");
7 const protocol = require("devtools/server/protocol");
8 const {method, RetVal} = protocol;
9 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
10 const {LongStringActor} = require("devtools/server/actors/string");
11 const {DebuggerServer} = require("devtools/server/main");
13 Cu.import("resource://gre/modules/PermissionsTable.jsm")
15 const APP_MAP = {
16 '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'firefox',
17 '{3550f703-e582-4d05-9a08-453d09bdfdc6}': 'thunderbird',
18 '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}': 'seamonkey',
19 '{718e30fb-e89b-41dd-9da7-e25a45638b28}': 'sunbird',
20 '{3c2e2abc-06d4-11e1-ac3b-374f68613e61}': 'b2g',
21 '{aa3c5121-dab2-40e2-81ca-7ea25febc110}': 'mobile/android',
22 '{a23983c0-fd0e-11dc-95ff-0800200c9a66}': 'mobile/xul'
23 }
25 exports.register = function(handle) {
26 handle.addGlobalActor(DeviceActor, "deviceActor");
27 };
29 exports.unregister = function(handle) {
30 };
32 let DeviceActor = protocol.ActorClass({
33 typeName: "device",
35 _desc: null,
37 _getAppIniString : function(section, key) {
38 let inifile = Services.dirsvc.get("GreD", Ci.nsIFile);
39 inifile.append("application.ini");
41 if (!inifile.exists()) {
42 inifile = Services.dirsvc.get("CurProcD", Ci.nsIFile);
43 inifile.append("application.ini");
44 }
46 if (!inifile.exists()) {
47 return undefined;
48 }
50 let iniParser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].getService(Ci.nsIINIParserFactory).createINIParser(inifile);
51 try {
52 return iniParser.getString(section, key);
53 } catch (e) {
54 return undefined;
55 }
56 },
58 _getSetting: function(name) {
59 let deferred = promise.defer();
61 if ("@mozilla.org/settingsService;1" in Cc) {
62 let settingsService = Cc["@mozilla.org/settingsService;1"].getService(Ci.nsISettingsService);
63 let req = settingsService.createLock().get(name, {
64 handle: (name, value) => deferred.resolve(value),
65 handleError: (error) => deferred.reject(error),
66 });
67 } else {
68 deferred.reject(new Error("No settings service"));
69 }
70 return deferred.promise;
71 },
73 getDescription: method(function() {
74 // Most of this code is inspired from Nightly Tester Tools:
75 // https://wiki.mozilla.org/Auto-tools/Projects/NightlyTesterTools
77 let appInfo = Services.appinfo;
78 let win = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
79 let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
81 desc = {
82 appid: appInfo.ID,
83 apptype: APP_MAP[appInfo.ID],
84 vendor: appInfo.vendor,
85 name: appInfo.name,
86 version: appInfo.version,
87 appbuildid: appInfo.appBuildID,
88 platformbuildid: appInfo.platformBuildID,
89 platformversion: appInfo.platformVersion,
90 geckobuildid: appInfo.platformBuildID,
91 geckoversion: appInfo.platformVersion,
92 changeset: this._getAppIniString("App", "SourceStamp"),
93 useragent: win.navigator.userAgent,
94 locale: Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry).getSelectedLocale("global"),
95 os: null,
96 hardware: "unknown",
97 processor: appInfo.XPCOMABI.split("-")[0],
98 compiler: appInfo.XPCOMABI.split("-")[1],
99 dpi: utils.displayDPI,
100 brandName: null,
101 channel: null,
102 profile: null,
103 width: win.screen.width,
104 height: win.screen.height
105 };
107 // Profile
108 let profd = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
109 let profservice = Cc["@mozilla.org/toolkit/profile-service;1"].getService(Ci.nsIToolkitProfileService);
110 var profiles = profservice.profiles;
111 while (profiles.hasMoreElements()) {
112 let profile = profiles.getNext().QueryInterface(Ci.nsIToolkitProfile);
113 if (profile.rootDir.path == profd.path) {
114 desc.profile = profile.name;
115 break;
116 }
117 }
119 if (!desc.profile) {
120 desc.profile = profd.leafName;
121 }
123 // Channel
124 try {
125 desc.channel = Services.prefs.getCharPref('app.update.channel');
126 } catch(e) {}
128 if (desc.apptype == "b2g") {
129 // B2G specific
130 desc.os = "B2G";
132 return this._getSetting('deviceinfo.hardware')
133 .then(value => desc.hardware = value)
134 .then(() => this._getSetting('deviceinfo.os'))
135 .then(value => desc.version = value)
136 .then(() => desc);
137 }
139 // Not B2G
140 desc.os = appInfo.OS;
141 let bundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
142 if (bundle) {
143 desc.brandName = bundle.GetStringFromName("brandFullName");
144 }
146 return desc;
148 }, {request: {},response: { value: RetVal("json")}}),
150 getWallpaper: method(function() {
151 let deferred = promise.defer();
152 this._getSetting("wallpaper.image").then((blob) => {
153 let FileReader = CC("@mozilla.org/files/filereader;1");
154 let reader = new FileReader();
155 let conn = this.conn;
156 reader.addEventListener("load", function() {
157 let str = new LongStringActor(conn, reader.result);
158 deferred.resolve(str);
159 });
160 reader.addEventListener("error", function() {
161 deferred.reject(reader.error);
162 });
163 reader.readAsDataURL(blob);
164 });
165 return deferred.promise;
166 }, {request: {},response: { value: RetVal("longstring")}}),
168 screenshotToDataURL: method(function() {
169 let window = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
170 let canvas = window.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
171 let width = window.innerWidth;
172 let height = window.innerHeight;
173 canvas.setAttribute('width', width);
174 canvas.setAttribute('height', height);
175 let context = canvas.getContext('2d');
176 let flags =
177 context.DRAWWINDOW_DRAW_CARET |
178 context.DRAWWINDOW_DRAW_VIEW |
179 context.DRAWWINDOW_USE_WIDGET_LAYERS;
180 context.drawWindow(window, 0, 0, width, height, 'rgb(255,255,255)', flags);
181 let dataURL = canvas.toDataURL('image/png')
182 return new LongStringActor(this.conn, dataURL);
183 }, {request: {},response: { value: RetVal("longstring")}}),
185 getRawPermissionsTable: method(function() {
186 return {
187 rawPermissionsTable: PermissionsTable,
188 UNKNOWN_ACTION: Ci.nsIPermissionManager.UNKNOWN_ACTION,
189 ALLOW_ACTION: Ci.nsIPermissionManager.ALLOW_ACTION,
190 DENY_ACTION: Ci.nsIPermissionManager.DENY_ACTION,
191 PROMPT_ACTION: Ci.nsIPermissionManager.PROMPT_ACTION
192 };
193 }, {request: {},response: { value: RetVal("json")}})
194 });
196 let DeviceFront = protocol.FrontClass(DeviceActor, {
197 initialize: function(client, form) {
198 protocol.Front.prototype.initialize.call(this, client);
199 this.actorID = form.deviceActor;
200 client.addActorPool(this);
201 this.manage(this);
202 },
204 screenshotToBlob: function() {
205 return this.screenshotToDataURL().then(longstr => {
206 return longstr.string().then(dataURL => {
207 let deferred = promise.defer();
208 longstr.release().then(null, Cu.reportError);
209 let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
210 req.open("GET", dataURL, true);
211 req.responseType = "blob";
212 req.onload = () => {
213 deferred.resolve(req.response);
214 };
215 req.onerror = () => {
216 deferred.reject(req.status);
217 }
218 req.send();
219 return deferred.promise;
220 });
221 });
222 },
223 });
225 const _knownDeviceFronts = new WeakMap();
227 exports.getDeviceFront = function(client, form) {
228 if (_knownDeviceFronts.has(client))
229 return _knownDeviceFronts.get(client);
231 let front = new DeviceFront(client, form);
232 _knownDeviceFronts.set(client, front);
233 return front;
234 }