Bug 1464990 - Allow easier testing Switchboard experiments; r=jchen,sebastian
authorPetru Lingurar <petru.lingurar@softvision.ro>
Thu, 21 Jun 2018 09:33:20 +0300
changeset 477457 46ea394f0c30fdfef5cc24baa78a667e9e0c1dc0
parent 477456 5dbc311fb93c0f6d4c82eb14fa9062984251ccfe
child 477458 776ba1aa0feee265e8b7ee7a570bac7114433a9a
push id9385
push userdluca@mozilla.com
push dateFri, 22 Jun 2018 15:47:18 +0000
treeherdermozilla-beta@82a9a1027e2b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjchen, sebastian
bugs1464990
milestone62.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 1464990 - Allow easier testing Switchboard experiments; r=jchen,sebastian Based on Sebastian's addon - https://github.com/pocmo/Addon-Switchboard-Experiments, this will allow to easily enable / disable Switchboard experiments, process that after Firefox 57 and the obsolescence of the addon was too cumbersome. MozReview-Commit-ID: 2EkYQ42Bd8B
mobile/android/chrome/content/aboutExperiments.js
mobile/android/chrome/content/aboutExperiments.xhtml
mobile/android/chrome/content/browser.js
mobile/android/chrome/jar.mn
mobile/android/components/AboutRedirector.js
mobile/android/components/MobileComponents.manifest
mobile/android/themes/core/aboutExperiments.css
mobile/android/themes/core/jar.mn
new file mode 100644
--- /dev/null
+++ b/mobile/android/chrome/content/aboutExperiments.js
@@ -0,0 +1,113 @@
+/* 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/. */
+
+"use strict";
+
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+  AndroidLog: "resource://gre/modules/AndroidLog.jsm",
+  EventDispatcher: "resource://gre/modules/Messaging.jsm",
+});
+
+const LOGTAG = "Experiments";
+const EXPERIMENTS_CONFIGURATION = "https://firefox.settings.services.mozilla.com/v1/buckets/fennec/collections/experiments/records";
+const Experiments = Services.wm.getMostRecentWindow("navigator:browser").Experiments;
+
+document.addEventListener("DOMContentLoaded", initList);
+
+function log(msg) {
+  AndroidLog.d(LOGTAG, msg);
+}
+
+function initList() {
+  const list = document.getElementById("list");
+  list.addEventListener("click", toggleOverride);
+
+  Promise.all([promiseEnabledExperiments(), promiseExperimentsConfiguration()]).then(values => {
+    const enabledExperiments = values[0];
+    const serverConfiguration = values[1];
+
+    serverConfiguration.data.forEach(function(experiment) {
+      try {
+        let item = document.createElement("li");
+        item.textContent = experiment.name;
+        item.setAttribute("name", experiment.name);
+        item.setAttribute("isEnabled", enabledExperiments.includes(experiment.name));
+        list.appendChild(item);
+      } catch (e) {
+          log(`Error while setting experiments list: ${e.error}`);
+      }
+    });
+  });
+}
+
+function toggleOverride(experiment) {
+  const item = experiment.originalTarget;
+  const name = item.getAttribute("name");
+  const isEnabled = item.getAttribute("isEnabled") === "true";
+
+  log(`toggleOverride: ${name}`);
+
+  Experiments.setOverride(name, !isEnabled);
+  item.setAttribute("isEnabled", !isEnabled);
+}
+
+/**
+ * Get the list of locally enabled experiments.
+ */
+function promiseEnabledExperiments() {
+  log("Getting the locally enabled experiments");
+
+  return EventDispatcher.instance.sendRequestForResult({
+    type: "Experiments:GetActive"
+  }).then(experiments => {
+    log("List of locally enabled experiments ready");
+    return experiments;
+  });
+}
+
+/**
+ * Fetch the list of experiments from server configuration.
+ */
+function promiseExperimentsConfiguration() {
+  log("Fetching server experiments");
+
+  return new Promise((resolve, reject) => {
+    const xhr = new XMLHttpRequest();
+
+    try {
+      xhr.open("GET", EXPERIMENTS_CONFIGURATION, true);
+    } catch (e) {
+      reject(`Error opening request: ${e}`);
+      return;
+    }
+
+    xhr.onerror = function(e) {
+      reject(`Error making request: ${e.error}`);
+    };
+
+    xhr.onload = function(event) {
+      if (xhr.readyState === 4) {
+        if (xhr.status === 200) {
+          try {
+            resolve(JSON.parse(xhr.responseText));
+          } catch (e) {
+            const errorMessage = `Error while parsing request: ${e}`;
+            log(errorMessage);
+            reject(errorMessage);
+          }
+        } else {
+          const errorMessage = `Request to ${url} returned status ${xhr.status}`;
+          log(errorMessage);
+          reject(errorMessage);
+        }
+      }
+      log("Finished fetching server experiments");
+    };
+
+    xhr.send(null);
+  });
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/chrome/content/aboutExperiments.xhtml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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/. -->
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Switchboard Experiments</title>
+    <meta name="viewport" content="width=device-width; user-scalable=0" />
+    <link rel="stylesheet" href="chrome://browser/skin/aboutBase.css" type="text/css"/>
+    <link rel="stylesheet" href="chrome://browser/skin/aboutExperiments.css" type="text/css"/>
+    <script type="application/javascript" src="chrome://browser/content/aboutExperiments.js"></script>
+  </head>
+
+  <body>
+    <ul id="list"/>
+  </body>
+</html>
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -5623,17 +5623,17 @@ var IdentityHandler = {
     if (aState & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) {
       return this.IDENTITY_MODE_VERIFIED;
     }
 
     if (aState & Ci.nsIWebProgressListener.STATE_IS_SECURE) {
       return this.IDENTITY_MODE_IDENTIFIED;
     }
 
-    let whitelist = /^about:(about|accounts|addons|buildconfig|cache|config|crashes|devices|downloads|fennec|firefox|feedback|home|license|logins|logo|memory|mozilla|networking|privatebrowsing|rights|serviceworkers|support|telemetry|webrtc)($|\?)/i;
+    let whitelist = /^about:(about|accounts|addons|buildconfig|cache|config|crashes|devices|downloads|experiments|fennec|firefox|feedback|home|license|logins|logo|memory|mozilla|networking|privatebrowsing|rights|serviceworkers|support|telemetry|webrtc)($|\?)/i;
     if (uri.schemeIs("about") && whitelist.test(uri.spec)) {
         return this.IDENTITY_MODE_CHROMEUI;
     }
 
     return this.IDENTITY_MODE_UNKNOWN;
   },
 
   getMixedDisplayMode: function getMixedDisplayMode(aState) {
--- a/mobile/android/chrome/jar.mn
+++ b/mobile/android/chrome/jar.mn
@@ -40,16 +40,18 @@ chrome.jar:
   content/PermissionsHelper.js         (content/PermissionsHelper.js)
   content/FeedHandler.js               (content/FeedHandler.js)
   content/Feedback.js                  (content/Feedback.js)
   content/Linkify.js                   (content/Linkify.js)
   content/CastingApps.js               (content/CastingApps.js)
   content/RemoteDebugger.js            (content/RemoteDebugger.js)
   content/aboutAccounts.xhtml          (content/aboutAccounts.xhtml)
   content/aboutAccounts.js             (content/aboutAccounts.js)
+  content/aboutExperiments.xhtml       (content/aboutExperiments.xhtml)
+  content/aboutExperiments.js          (content/aboutExperiments.js)
   content/aboutLogins.xhtml            (content/aboutLogins.xhtml)
   content/aboutLogins.js               (content/aboutLogins.js)
 #ifndef RELEASE_OR_BETA
   content/WebcompatReporter.js         (content/WebcompatReporter.js)
 #endif
   content/ExtensionPermissions.js      (content/ExtensionPermissions.js)
 
 % content branding %content/branding/
--- a/mobile/android/components/AboutRedirector.js
+++ b/mobile/android/components/AboutRedirector.js
@@ -62,16 +62,21 @@ var modules = {
   logins: {
     uri: "chrome://browser/content/aboutLogins.xhtml",
     privileged: true
   },
   accounts: {
     uri: "chrome://browser/content/aboutAccounts.xhtml",
     privileged: true
   },
+  experiments: {
+    uri: "chrome://browser/content/aboutExperiments.xhtml",
+    privileged: true,
+    hide: true
+  },
 };
 
 function AboutRedirector() {}
 AboutRedirector.prototype = {
   QueryInterface: ChromeUtils.generateQI([Ci.nsIAboutModule]),
   classID: Components.ID("{322ba47e-7047-4f71-aebf-cb7d69325cd9}"),
 
   _getModuleInfo: function(aURI) {
--- a/mobile/android/components/MobileComponents.manifest
+++ b/mobile/android/components/MobileComponents.manifest
@@ -9,16 +9,17 @@ contract @mozilla.org/network/protocol/a
 contract @mozilla.org/network/protocol/about;1?what=home {322ba47e-7047-4f71-aebf-cb7d69325cd9}
 contract @mozilla.org/network/protocol/about;1?what=downloads {322ba47e-7047-4f71-aebf-cb7d69325cd9}
 contract @mozilla.org/network/protocol/about;1?what=reader {322ba47e-7047-4f71-aebf-cb7d69325cd9}
 contract @mozilla.org/network/protocol/about;1?what=feedback {322ba47e-7047-4f71-aebf-cb7d69325cd9}
 contract @mozilla.org/network/protocol/about;1?what=privatebrowsing {322ba47e-7047-4f71-aebf-cb7d69325cd9}
 contract @mozilla.org/network/protocol/about;1?what=blocked {322ba47e-7047-4f71-aebf-cb7d69325cd9}
 contract @mozilla.org/network/protocol/about;1?what=accounts {322ba47e-7047-4f71-aebf-cb7d69325cd9}
 contract @mozilla.org/network/protocol/about;1?what=logins {322ba47e-7047-4f71-aebf-cb7d69325cd9}
+contract @mozilla.org/network/protocol/about;1?what=experiments {322ba47e-7047-4f71-aebf-cb7d69325cd9}
 
 # DirectoryProvider.js
 component {ef0f7a87-c1ee-45a8-8d67-26f586e46a4b} DirectoryProvider.js
 contract @mozilla.org/browser/directory-provider;1 {ef0f7a87-c1ee-45a8-8d67-26f586e46a4b}
 category xpcom-directory-providers browser-directory-provider @mozilla.org/browser/directory-provider;1
 
 # stylesheets
 category agent-style-sheets browser-content-stylesheet chrome://geckoview/skin/content.css
new file mode 100644
--- /dev/null
+++ b/mobile/android/themes/core/aboutExperiments.css
@@ -0,0 +1,19 @@
+/* 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/. */
+
+ul {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+}
+li {
+  padding: 25px;
+  margin-bottom: 5px;
+}
+li[isEnabled="true"] {
+  background-color: #c5e1a5;
+}
+li[isEnabled="false"] {
+  background-color: #ef9a9a;
+}
\ No newline at end of file
--- a/mobile/android/themes/core/jar.mn
+++ b/mobile/android/themes/core/jar.mn
@@ -7,16 +7,17 @@
 chrome.jar:
 % skin browser classic/1.0 %skin/
   skin/aboutPage.css                        (aboutPage.css)
   skin/about.css                            (about.css)
   skin/aboutAccounts.css                    (aboutAccounts.css)
   skin/aboutAddons.css                      (aboutAddons.css)
   skin/aboutBase.css                        (aboutBase.css)
   skin/aboutDownloads.css                   (aboutDownloads.css)
+  skin/aboutExperiments.css                 (aboutExperiments.css)
   skin/aboutMemory.css                      (aboutMemory.css)
   skin/aboutPrivateBrowsing.css             (aboutPrivateBrowsing.css)
   skin/aboutReader.css                      (aboutReader.css)
   skin/aboutSupport.css                     (aboutSupport.css)
   skin/config.css                           (config.css)
   skin/defines.css                          (defines.css)
   skin/netError.css                         (netError.css)
   skin/spinner.css                          (spinner.css)