|
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/. */ |
|
4 |
|
5 const Cu = Components.utils; |
|
6 const Ci = Components.interfaces; |
|
7 Cu.import("resource://gre/modules/Services.jsm"); |
|
8 Cu.import("resource:///modules/devtools/gDevTools.jsm"); |
|
9 |
|
10 const {Simulator} = Cu.import("resource://gre/modules/devtools/Simulator.jsm") |
|
11 const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm"); |
|
12 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); |
|
13 const {require} = devtools; |
|
14 |
|
15 const {ConnectionManager, Connection} = require("devtools/client/connection-manager"); |
|
16 const {getDeviceFront} = require("devtools/server/actors/device"); |
|
17 const ConnectionStore = require("devtools/app-manager/connection-store"); |
|
18 const DeviceStore = require("devtools/app-manager/device-store"); |
|
19 const simulatorsStore = require("devtools/app-manager/simulators-store"); |
|
20 const adbStore = require("devtools/app-manager/builtin-adb-store"); |
|
21 |
|
22 window.addEventListener("unload", function onUnload() { |
|
23 window.removeEventListener("unload", onUnload); |
|
24 UI.destroy(); |
|
25 }); |
|
26 |
|
27 let UI = { |
|
28 init: function() { |
|
29 this.useFloatingScrollbarsIfNeeded(); |
|
30 let connections = ConnectionManager.connections; |
|
31 if (connections.length > 0) { |
|
32 let hash = window.location.hash; |
|
33 if (hash) { |
|
34 let res = (/cid=([^&]+)/).exec(hash) |
|
35 if (res) { |
|
36 let [,cid] = res; |
|
37 this.connection = connections.filter((({uid}) => uid == cid))[0]; |
|
38 } |
|
39 } |
|
40 if (!this.connection) { |
|
41 // We take the first connection available. |
|
42 this.connection = connections[0]; |
|
43 } |
|
44 } else { |
|
45 let host = Services.prefs.getCharPref("devtools.debugger.remote-host"); |
|
46 let port = Services.prefs.getIntPref("devtools.debugger.remote-port"); |
|
47 this.connection = ConnectionManager.createConnection(host, port); |
|
48 } |
|
49 |
|
50 window.location.hash = "cid=" + this.connection.uid; |
|
51 window.parent.postMessage(JSON.stringify({name:"connection",cid:this.connection.uid}), "*"); |
|
52 |
|
53 this.store = Utils.mergeStores({ |
|
54 "device": new DeviceStore(this.connection), |
|
55 "connection": new ConnectionStore(this.connection), |
|
56 "simulators": simulatorsStore, |
|
57 "adb": adbStore |
|
58 }); |
|
59 |
|
60 let pre = document.querySelector("#logs > pre"); |
|
61 pre.textContent = this.connection.logs; |
|
62 pre.scrollTop = pre.scrollTopMax; |
|
63 this.connection.on(Connection.Events.NEW_LOG, this._onNewLog); |
|
64 |
|
65 this.template = new Template(document.body, this.store, Utils.l10n); |
|
66 this.template.start(); |
|
67 |
|
68 this._onSimulatorConnected = this._onSimulatorConnected.bind(this); |
|
69 this._onSimulatorDisconnected = this._onSimulatorDisconnected.bind(this); |
|
70 }, |
|
71 |
|
72 destroy: function() { |
|
73 this.store.destroy(); |
|
74 this.connection.off(Connection.Events.NEW_LOG, this._onNewLog); |
|
75 this.template.destroy(); |
|
76 }, |
|
77 |
|
78 _onNewLog: function(event, str) { |
|
79 let pre = document.querySelector("#logs > pre"); |
|
80 pre.textContent += "\n" + str; |
|
81 pre.scrollTop = pre.scrollTopMax; |
|
82 }, |
|
83 |
|
84 useFloatingScrollbarsIfNeeded: function() { |
|
85 if (Services.appinfo.OS == "Darwin") { |
|
86 return; |
|
87 } |
|
88 let scrollbarsUrl = Services.io.newURI("chrome://browser/skin/devtools/floating-scrollbars-light.css", null, null); |
|
89 let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); |
|
90 winUtils.loadSheet(scrollbarsUrl, winUtils.AGENT_SHEET); |
|
91 let computedStyle = window.getComputedStyle(document.documentElement); |
|
92 if (computedStyle) { // Force a reflow to take the new css into account |
|
93 let display = computedStyle.display; // Save display value |
|
94 document.documentElement.style.display = "none"; |
|
95 window.getComputedStyle(document.documentElement).display; // Flush |
|
96 document.documentElement.style.display = display; // Restore |
|
97 } |
|
98 }, |
|
99 |
|
100 disconnect: function() { |
|
101 this.connection.disconnect(); |
|
102 }, |
|
103 |
|
104 connect: function() { |
|
105 this.connection.connect(); |
|
106 }, |
|
107 |
|
108 editConnectionParameters: function() { |
|
109 document.body.classList.add("edit-connection"); |
|
110 document.querySelector("input.host").focus(); |
|
111 }, |
|
112 |
|
113 saveConnectionInfo: function() { |
|
114 document.body.classList.remove("edit-connection"); |
|
115 document.querySelector("#connect-button").focus(); |
|
116 let host = document.querySelector("input.host").value; |
|
117 let port = document.querySelector("input.port").value; |
|
118 this.connection.port = port; |
|
119 this.connection.host = host; |
|
120 Services.prefs.setCharPref("devtools.debugger.remote-host", host); |
|
121 Services.prefs.setIntPref("devtools.debugger.remote-port", port); |
|
122 }, |
|
123 |
|
124 showSimulatorList: function() { |
|
125 document.body.classList.add("show-simulators"); |
|
126 }, |
|
127 |
|
128 cancelShowSimulatorList: function() { |
|
129 document.body.classList.remove("show-simulators"); |
|
130 }, |
|
131 |
|
132 installSimulator: function() { |
|
133 let url = "https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Simulator"; |
|
134 window.open(url); |
|
135 }, |
|
136 |
|
137 startSimulator: function(version) { |
|
138 this._portBeforeSimulatorStarted = this.connection.port; |
|
139 let port = ConnectionManager.getFreeTCPPort(); |
|
140 let simulator = Simulator.getByVersion(version); |
|
141 if (!simulator) { |
|
142 this.connection.log("Error: can't find simulator: " + version); |
|
143 return; |
|
144 } |
|
145 if (!simulator.launch) { |
|
146 this.connection.log("Error: invalid simulator: " + version); |
|
147 return; |
|
148 } |
|
149 this.connection.log("Found simulator: " + version); |
|
150 this.connection.log("Starting simulator..."); |
|
151 |
|
152 this.simulator = simulator; |
|
153 this.simulator.launch({ port: port }) |
|
154 .then(() => { |
|
155 this.connection.log("Simulator ready. Connecting."); |
|
156 this.connection.port = port; |
|
157 this.connection.host = "localhost"; |
|
158 this.connection.once("connected", |
|
159 this._onSimulatorConnected); |
|
160 this.connection.once("disconnected", |
|
161 this._onSimulatorDisconnected); |
|
162 this.connection.keepConnecting = true; |
|
163 this.connection.connect(); |
|
164 }); |
|
165 document.body.classList.remove("show-simulators"); |
|
166 }, |
|
167 |
|
168 _onSimulatorConnected: function() { |
|
169 this.connection.log("Connected to simulator."); |
|
170 this.connection.keepConnecting = false; |
|
171 |
|
172 // This doesn't change the current (successful) connection, |
|
173 // but makes sure that when the simulator is disconnected, the |
|
174 // connection doesn't end up with a random port number (from |
|
175 // getFreeTCPPort). |
|
176 this.connection.port = this._portBeforeSimulatorStarted; |
|
177 }, |
|
178 |
|
179 _onSimulatorDisconnected: function() { |
|
180 this.connection.off("connected", this._onSimulatorConnected); |
|
181 }, |
|
182 |
|
183 connectToAdbDevice: function(name) { |
|
184 let device = Devices.getByName(name); |
|
185 device.connect().then((port) => { |
|
186 this.connection.host = "localhost"; |
|
187 this.connection.port = port; |
|
188 this.connect(); |
|
189 }); |
|
190 }, |
|
191 |
|
192 screenshot: function() { |
|
193 this.connection.client.listTabs( |
|
194 response => { |
|
195 let front = getDeviceFront(this.connection.client, response); |
|
196 front.screenshotToBlob().then(blob => { |
|
197 let topWindow = Services.wm.getMostRecentWindow("navigator:browser"); |
|
198 let gBrowser = topWindow.gBrowser; |
|
199 let url = topWindow.URL.createObjectURL(blob); |
|
200 let tab = gBrowser.selectedTab = gBrowser.addTab(url); |
|
201 tab.addEventListener("TabClose", function onTabClose() { |
|
202 tab.removeEventListener("TabClose", onTabClose, false); |
|
203 topWindow.URL.revokeObjectURL(url); |
|
204 }, false); |
|
205 }).then(null, console.error); |
|
206 } |
|
207 ); |
|
208 }, |
|
209 } |