Bug 912892 - [app manager] simulator launch UI. r=ochameau
authorPaul Rouget <paul@mozilla.com>
Tue, 10 Sep 2013 11:42:00 +0200
changeset 159569 d9b79f9842c15cc966820f46bebad5b43903ad29
parent 159568 99f92e712d48c6df8087020530c2405bf9ce3a20
child 159570 22d47b7958707551a10011d262784c839deed0da
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs912892
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 912892 - [app manager] simulator launch UI. r=ochameau
browser/app/profile/firefox.js
browser/devtools/app-manager/content/connection-footer.js
browser/devtools/app-manager/content/connection-footer.xhtml
browser/devtools/app-manager/simulators-store.js
browser/locales/en-US/chrome/browser/devtools/app-manager.dtd
browser/themes/shared/devtools/app-manager/connection-footer.css
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1063,16 +1063,17 @@ pref("devtools.errorconsole.enabled", fa
 // Developer toolbar and GCLI preferences
 pref("devtools.toolbar.enabled", true);
 pref("devtools.toolbar.visible", false);
 pref("devtools.gcli.allowSet", false);
 pref("devtools.commands.dir", "");
 
 // Disable the app manager
 pref("devtools.appmanager.enabled", false);
+pref("devtools.appmanager.simulatorInstallPage", "https://addons.mozilla.org/firefox/addon/firefox-os-simulator/");
 
 // Toolbox preferences
 pref("devtools.toolbox.footer.height", 250);
 pref("devtools.toolbox.sidebar.width", 500);
 pref("devtools.toolbox.host", "bottom");
 pref("devtools.toolbox.selectedTool", "webconsole");
 pref("devtools.toolbox.toolbarSpec", '["paintflashing toggle","tilt toggle","scratchpad","resize toggle"]');
 pref("devtools.toolbox.sideEnabled", true);
--- a/browser/devtools/app-manager/content/connection-footer.js
+++ b/browser/devtools/app-manager/content/connection-footer.js
@@ -2,22 +2,24 @@
  * 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/. */
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
+const {Simulator} = Cu.import("resource://gre/modules/devtools/Simulator.jsm")
 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const {require} = devtools;
 
 const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
 const ConnectionStore = require("devtools/app-manager/connection-store");
 const DeviceStore = require("devtools/app-manager/device-store");
+const simulatorsStore = require("devtools/app-manager/simulators-store");
 
 let UI = {
   init: function() {
     this.useFloatingScrollbarsIfNeeded();
     let connections = ConnectionManager.connections;
     if (connections.length > 0) {
       let hash = window.location.hash;
       if (hash) {
@@ -38,16 +40,17 @@ let UI = {
     }
 
     window.location.hash = "cid=" + this.connection.uid;
     window.parent.postMessage(JSON.stringify({name:"connection",cid:this.connection.uid}), "*");
 
     this.store = Utils.mergeStores({
       "device": new DeviceStore(this.connection),
       "connection": new ConnectionStore(this.connection),
+      "simulators": simulatorsStore,
     });
 
     let pre = document.querySelector("#logs > pre");
     pre.textContent = this.connection.logs;
     pre.scrollTop = pre.scrollTopMax;
     this.connection.on(Connection.Events.NEW_LOG, (event, str) => {
       pre.textContent += "\n" + str;
       pre.scrollTop = pre.scrollTopMax;
@@ -91,9 +94,52 @@ let UI = {
     document.querySelector("#connect-button").focus();
     let host = document.querySelector("input.host").value;
     let port = document.querySelector("input.port").value;
     this.connection.port = port;
     this.connection.host = host;
     Services.prefs.setCharPref("devtools.debugger.remote-host", host);
     Services.prefs.setIntPref("devtools.debugger.remote-port", port);
   },
+
+  showSimulatorList: function() {
+    document.body.classList.add("show-simulators");
+  },
+
+  cancelShowSimulatorList: function() {
+    document.body.classList.remove("show-simulators");
+  },
+
+  installSimulator: function() {
+    let url = Services.prefs.getCharPref("devtools.appmanager.simulatorInstallPage");
+    window.open(url);
+  },
+
+  startSimulator: function(version) {
+    let port = ConnectionManager.getFreeTCPPort();
+    let simulator = Simulator.getByVersion(version);
+    if (!simulator) {
+      this.connection.log("Error: can't find simulator: " + version);
+      return;
+    }
+    if (!simulator.launch) {
+      this.connection.log("Error: invalid simulator: " + version);
+      return;
+    }
+    this.connection.log("Found simulator: " + version);
+    this.connection.log("Starting simulator...");
+
+    this.simulator = simulator;
+    this.simulator.launch({ port: port })
+      .then(() => {
+        this.connection.log("Simulator ready. Connecting.");
+        this.connection.port = port;
+        this.connection.host = "localhost";
+        this.connection.once("connected", function() {
+          this.connection.log("Connected to simulator.");
+          this.connection.keepConnecting = false;
+        });
+        this.connection.keepConnecting = true;
+        this.connection.connect();
+      });
+    document.body.classList.remove("show-simulators");
+  },
 }
--- a/browser/devtools/app-manager/content/connection-footer.xhtml
+++ b/browser/devtools/app-manager/content/connection-footer.xhtml
@@ -33,19 +33,19 @@
         <!-- Disconnected -->
         <div id="banner-disconnected" class="banner">
           <div class="connected-indicator"></div>
           <div class="banner-box">
             <div class="banner-content">
               <span>&connection.notConnected;</span>
               <button class="action-primary left" onclick="UI.connect()" id="connect-button" template='{"type":"localizedContent","property":"connection.connectTo","paths":["connection.host","connection.port"]}'></button>
               <button class="right" onclick="UI.editConnectionParameters()">&connection.changeHostAndPort;</button>
-              <div id="start-simulator-box" template='{"type":"attribute","path":"simulators.versions.length","name":"simulators-count"}'>
+              <div id="start-simulator-box">
                 <span>&connection.or;</span>
-                <button id="start-simulator-button" class="action-primary" onclick="UI.startSimulator()">&connection.startSimulator;</button>
+                <button id="start-simulator-button" class="action-primary" onclick="UI.showSimulatorList()">&connection.startSimulator;</button>
               </div>
             </div>
           </div>
         </div>
 
         <!-- Connecting -->
         <div id="banner-connecting" class="banner">
           <div class="connected-indicator"></div>
@@ -76,23 +76,50 @@
                 <input class="host" template='{"type":"attribute","path":"connection.host","name":"value"}'></input>
                 <input class="port" pattern="\d+" template='{"type":"attribute","path":"connection.port","name":"value"}' type="number"></input>
                 <button type="submit">&connection.saveConnectionInfo;</button>
               </form>
             </div>
           </div>
         </div>
 
+        <!-- Simulator -->
+        <div id="banner-simulators" class="banner" template='{"type":"attribute","path":"simulators.versions.length","name":"simulator-count"}'>
+          <div class="connected-indicator"></div>
+          <div class="banner-box">
+            <div class="banner-content">
+              <div class="no-simulator">
+                <span>&connection.noSimulatorInstalled;</span>
+                <button class="action-primary" onclick="UI.installSimulator()">&connection.installFirstSimulator;</button>
+              </div>
+              <div class="found-simulator">
+                <span template-loop='{"arrayPath":"simulators.versions","childSelector":"#simulator-item-template"}'></span>
+                <button class="action-primary" onclick="UI.installSimulator()">&connection.installAnotherSimulator;</button>
+              </div>
+              <button class="action-cancel" onclick="UI.cancelShowSimulatorList()">&connection.cancel;</button>
+            </div>
+          </div>
+        </div>
+
+
         <!-- Logs -->
         <div id="banner-logs">
         <div id="logs" class="banner-box">
           <pre></pre>
         </div>
         </div>
 
       </div>
     </div>
   </body>
 
+  <template id="simulator-item-template">
+  <span>
+    <button class="simulator-item" onclick="UI.startSimulator(this.dataset.version)" template='{"type":"attribute","path":"version","name":"data-version"}'>
+      <span template='{"type":"textContent", "path":"version"}'></span>
+    </button>
+  </span>
+  </template>
+
   <script type="application/javascript;version=1.8" src="utils.js"></script>
   <script type="application/javascript;version=1.8" src="template.js"></script>
   <script type="application/javascript;version=1.8" src="connection-footer.js"></script>
 </html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/simulators-store.js
@@ -0,0 +1,21 @@
+/* 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/. */
+
+const {Cu} = require("chrome");
+const ObservableObject = require("devtools/shared/observable-object");
+const {Simulator} = Cu.import("resource://gre/modules/devtools/Simulator.jsm");
+
+let store = new ObservableObject({versions:[]});
+
+function feedStore() {
+  store.object.versions = Simulator.availableVersions().map(v => {
+    return {version:v}
+  });
+}
+
+Simulator.on("register", feedStore);
+Simulator.on("unregister", feedStore);
+feedStore();
+
+module.exports = store;
--- a/browser/locales/en-US/chrome/browser/devtools/app-manager.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/app-manager.dtd
@@ -27,16 +27,19 @@
 <!ENTITY connection.notConnected "Not Connected">
 <!ENTITY connection.changeHostAndPort "Change">
 <!ENTITY connection.startSimulator "Start Simulator">
 <!ENTITY connection.saveConnectionInfo "Save">
 <!ENTITY connection.connecting "Connecting…">
 <!ENTITY connection.disconnecting "Disconnecting…">
 <!ENTITY connection.cancel "Cancel">
 <!ENTITY connection.or "or">
+<!ENTITY connection.noSimulatorInstalled "No simulator installed.">
+<!ENTITY connection.installFirstSimulator "Install simulator.">
+<!ENTITY connection.installAnotherSimulator "Add">
 
 <!ENTITY projects.localApps "Local Apps">
 <!ENTITY projects.addApp "Add">
 <!ENTITY projects.addPackaged "Add Packaged App">
 <!ENTITY projects.addHosted "Add Hosted App">
 <!ENTITY projects.title "Local Apps">
 <!ENTITY projects.appDetails "App Details">
 <!ENTITY projects.removeApp "Remove">
--- a/browser/themes/shared/devtools/app-manager/connection-footer.css
+++ b/browser/themes/shared/devtools/app-manager/connection-footer.css
@@ -28,20 +28,22 @@
 
 #connection-footer[status="connected"]     #banner-connected,
 #connection-footer[status="connecting"]    #banner-connecting,
 #connection-footer[status="disconnected"]  #banner-disconnected,
 #connection-footer[status="disconnecting"] #banner-disconnecting {
   display: flex;
 }
 
+body.show-simulators .banner,
 body.edit-connection .banner {
   display: none !important;
 }
 
+body.show-simulators #banner-simulators,
 body.edit-connection #banner-editing {
   display: flex !important;
 }
 
 #banner-logs {
   width: 40%;
   display: flex;
 }
@@ -65,20 +67,16 @@ body.edit-connection #banner-editing {
 #banner-connected > .banner-box {
   align-items: flex-start;
 }
 
 #start-simulator-box {
   display: inline;
 }
 
-#start-simulator-box[simulators-count="0"] {
-  display: none;
-}
-
 /************** PIXELS **************/
 
 * {
   margin: 0;
   padding: 0;
   -moz-box-sizing: border-box;
   font-size: 0.9rem;
 }
@@ -188,13 +186,23 @@ button.action-cancel {
   flex: 0 0 10px;
 }
 
 #banner-connected .connected-indicator,
 #banner-connecting .connected-indicator {
   background: linear-gradient(to bottom, #69B8FF, #339FFF );
 }
 
+#banner-simulators .connected-indicator,
 #banner-disconnected .connected-indicator,
 #banner-editing .connected-indicator,
 #banner-disconnecting .connected-indicator {
   background: linear-gradient(to bottom, #375A87, #1C4375 );
 }
+
+#banner-simulators .banner-content > * {
+  display: inline-block;
+}
+
+#banner-simulators[simulator-count="0"] .found-simulator,
+#banner-simulators:not([simulator-count="0"]) .no-simulator {
+  display: none;
+}