merge fx-team to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 09 Dec 2015 11:46:15 +0100
changeset 310028 40b58759c962bf1a8dbf8b56a7227778dfdcfa50
parent 310020 f91bcf823a70399d593c2945b7da1d179591de60 (current diff)
parent 310027 7acf3c6168d5af71e651c44427ecb5017041d87c (diff)
child 310074 319be5e7ce3061c7c16f24d750b6dacdbcac4c35
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone45.0a1
first release with
nightly linux32
40b58759c962 / 45.0a1 / 20151209030228 / files
nightly linux64
40b58759c962 / 45.0a1 / 20151209030228 / files
nightly mac
40b58759c962 / 45.0a1 / 20151209030228 / files
nightly win32
40b58759c962 / 45.0a1 / 20151209030228 / files
nightly win64
40b58759c962 / 45.0a1 / 20151209030228 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge fx-team to mozilla-central a=merge
mobile/android/base/docs/adjust.rst
mobile/android/base/docs/gradle.rst
mobile/android/base/docs/localeswitching.rst
mobile/android/base/docs/uitelemetry.rst
--- a/browser/extensions/loop/content/panels/js/roomStore.js
+++ b/browser/extensions/loop/content/panels/js/roomStore.js
@@ -204,17 +204,16 @@ loop.store = loop.store || {};
         roomList: this._storeState.rooms.filter(function(room) {
           return room.roomToken !== removedRoomData.roomToken;
         })
       }));
     },
 
     /**
      * Executed when the user switches accounts.
-     *
      */
     _onRoomsRefresh: function() {
       this.dispatchAction(new sharedActions.UpdateRoomList({
         roomList: []
       }));
     },
 
     /**
@@ -335,17 +334,17 @@ loop.store = loop.store || {};
     /**
      * Emails a room url.
      *
      * @param  {sharedActions.EmailRoomUrl} actionData The action data.
      */
     emailRoomUrl: function(actionData) {
       var from = actionData.from;
       loop.shared.utils.composeCallUrlEmail(actionData.roomUrl, null,
-        actionData.roomDescription, from);
+        actionData.roomDescription);
 
       var bucket = this._constants.SHARING_ROOM_URL["EMAIL_FROM_" + (from || "").toUpperCase()];
       if (typeof bucket === "undefined") {
         console.error("No URL sharing type bucket found for '" + from + "'");
         return;
       }
       loop.requestMulti(
         ["NotifyUITour", "Loop:RoomURLEmailed"],
@@ -381,20 +380,18 @@ loop.store = loop.store || {};
       loop.requestMulti(
         ["SocialShareRoom", actionData.provider.origin, actionData.roomUrl,
          shareTitle, shareBody],
         ["NotifyUITour", "Loop:RoomURLShared"]);
     },
 
     /**
      * Open the share panel to add a Social share provider.
-     *
-     * @param {sharedActions.AddSocialShareProvider} actionData The action data.
      */
-    addSocialShareProvider: function(actionData) {
+    addSocialShareProvider: function() {
       loop.request("AddSocialShareProvider");
     },
 
     /**
      * Creates a new room.
      *
      * @param {sharedActions.DeleteRoom} actionData The action data.
      */
--- a/browser/extensions/loop/content/shared/js/linkifiedTextView.js
+++ b/browser/extensions/loop/content/shared/js/linkifiedTextView.js
@@ -1,16 +1,16 @@
 /* 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/. */
 
 var loop = loop || {};
 loop.shared = loop.shared || {};
 loop.shared.views = loop.shared.views || {};
-loop.shared.views.LinkifiedTextView = (function(mozL10n) {
+loop.shared.views.LinkifiedTextView = (function() {
   "use strict";
 
   /**
    * Given a rawText property, renderer a version of that text with any
    * links starting with http://, https://, or ftp:// as actual clickable
    * links inside a <p> container.
    */
   var LinkifiedTextView = React.createClass({displayName: "LinkifiedTextView",
@@ -108,9 +108,9 @@ loop.shared.views.LinkifiedTextView = (f
       return (
         React.createElement("p", null, this.parseStringToElements(this.props.rawText))
       );
     }
   });
 
   return LinkifiedTextView;
 
-})(navigator.mozL10n || document.mozL10n);
+})();
--- a/browser/extensions/loop/content/shared/js/linkifiedTextView.jsx
+++ b/browser/extensions/loop/content/shared/js/linkifiedTextView.jsx
@@ -1,16 +1,16 @@
 /* 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/. */
 
 var loop = loop || {};
 loop.shared = loop.shared || {};
 loop.shared.views = loop.shared.views || {};
-loop.shared.views.LinkifiedTextView = (function(mozL10n) {
+loop.shared.views.LinkifiedTextView = (function() {
   "use strict";
 
   /**
    * Given a rawText property, renderer a version of that text with any
    * links starting with http://, https://, or ftp:// as actual clickable
    * links inside a <p> container.
    */
   var LinkifiedTextView = React.createClass({
@@ -108,9 +108,9 @@ loop.shared.views.LinkifiedTextView = (f
       return (
         <p>{this.parseStringToElements(this.props.rawText)}</p>
       );
     }
   });
 
   return LinkifiedTextView;
 
-})(navigator.mozL10n || document.mozL10n);
+})();
--- a/browser/extensions/loop/content/shared/js/otSdkDriver.js
+++ b/browser/extensions/loop/content/shared/js/otSdkDriver.js
@@ -689,17 +689,17 @@ loop.OTSdkDriver = (function() {
 
               this.dispatcher.dispatch(
                 new sharedActions.ReceivedTextChatMessage(message));
             } catch (ex) {
               console.error("Failed to process incoming chat message", ex);
             }
           }.bind(this),
 
-          close: function(e) {
+          close: function() {
             // XXX We probably want to dispatch and handle this somehow.
             console.log("Subscribed data channel closed!");
           }
         });
 
         this._subscriberChannel = channel;
         this._checkDataChannelsAvailable();
       }.bind(this));
@@ -708,20 +708,18 @@ loop.OTSdkDriver = (function() {
     /**
      * Handles receiving the signal that the other end of the connection
      * has subscribed to the stream and we're ready to setup the data channel.
      *
      * We create the publisher data channel when we get the signal as it means
      * that the remote client is setup for data
      * channels. Getting the data channel for the subscriber is handled
      * separately when the subscription completes.
-     *
-     * @param {OT.SignalEvent} event Details of the signal received.
      */
-    _onReadyForDataChannel: function(event) {
+    _onReadyForDataChannel: function() {
       // If we don't want data channels, just ignore the message. We haven't
       // send the other side a message, so it won't display anything.
       if (!this._useDataChannels) {
         return;
       }
 
       // This won't work until a subscriber exists for this publisher
       this.publisher._.getDataChannel("text", {}, function(err, channel) {
@@ -729,17 +727,17 @@ loop.OTSdkDriver = (function() {
           console.error(err);
           this._notifyMetricsEvent("sdk.datachannel.pub." + err.message);
           return;
         }
 
         this._publisherChannel = channel;
 
         channel.on({
-          close: function(e) {
+          close: function() {
             // XXX We probably want to dispatch and handle this somehow.
             console.log("Published data channel closed!");
           }
         });
 
         this._checkDataChannelsAvailable();
       }.bind(this));
     },
@@ -986,42 +984,38 @@ loop.OTSdkDriver = (function() {
     },
 
     /**
      * Handle the (remote) VideoEnabled event from the subscriber object
      * by dispatching an action with the (hidden) video element from
      * which to copy the stream when attaching it to visible video element
      * that the views control directly.
      *
-     * @param event {OT.VideoEnabledChangedEvent} from the SDK
-     *
      * @see https://tokbox.com/opentok/libraries/client/js/reference/VideoEnabledChangedEvent.html
      * @private
      */
-    _onVideoEnabled: function(event) {
+    _onVideoEnabled: function() {
       var sdkSubscriberVideo = this._mockSubscribeEl.querySelector("video");
       if (!sdkSubscriberVideo) {
         console.error("sdkSubscriberVideo unexpectedly falsy!");
       }
 
       this.dispatcher.dispatch(new sharedActions.RemoteVideoStatus({
         videoEnabled: true
       }));
     },
 
     /**
      * Handle the SDK disabling of remote video by dispatching the
      * appropriate event.
      *
-     * @param event {OT.VideoEnabledChangedEvent) from the SDK
-     *
      * @see https://tokbox.com/opentok/libraries/client/js/reference/VideoEnabledChangedEvent.html
      * @private
      */
-    _onVideoDisabled: function(event) {
+    _onVideoDisabled: function() {
       this.dispatcher.dispatch(new sharedActions.RemoteVideoStatus({
         videoEnabled: false
       }));
     },
 
     /**
      * Publishes the local stream if the session is connected
      * and the publisher is ready.
--- a/browser/extensions/loop/content/shared/js/textChatStore.js
+++ b/browser/extensions/loop/content/shared/js/textChatStore.js
@@ -3,18 +3,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var loop = loop || {};
 loop.store = loop.store || {};
 
 loop.store.TextChatStore = (function() {
   "use strict";
 
-  var sharedActions = loop.shared.actions;
-
   var CHAT_MESSAGE_TYPES = loop.store.CHAT_MESSAGE_TYPES = {
     RECEIVED: "recv",
     SENT: "sent",
     SPECIAL: "special"
   };
 
   var CHAT_CONTENT_TYPES = loop.shared.utils.CHAT_CONTENT_TYPES;
 
--- a/browser/extensions/loop/content/shared/js/utils.js
+++ b/browser/extensions/loop/content/shared/js/utils.js
@@ -392,19 +392,18 @@ var inChrome = typeof Components != "und
 
   /**
    * Generates and opens a mailto: url with call URL information prefilled.
    * Note: This only works for Desktop.
    *
    * @param {String} callUrl              The call URL.
    * @param {String} [recipient]          The recipient email address (optional).
    * @param {String} [contextDescription] The context description (optional).
-   * @param {String} [from]               The area from which this function is called.
    */
-  function composeCallUrlEmail(callUrl, recipient, contextDescription, from) {
+  function composeCallUrlEmail(callUrl, recipient, contextDescription) {
     if (!isDesktop()) {
       console.warn("composeCallUrlEmail isn't available for Loop standalone.");
       return;
     }
 
     var subject, body;
     var footer = mozL10n.get("share_email_footer2");
     if (contextDescription) {
--- a/browser/extensions/loop/standalone/content/js/standaloneAppStore.js
+++ b/browser/extensions/loop/standalone/content/js/standaloneAppStore.js
@@ -7,17 +7,16 @@ loop.store = loop.store || {};
 
 /**
  * Manages the standalone app controller view. Used to get
  * the window data and store the window type.
  */
 loop.store.StandaloneAppStore = (function() {
   "use strict";
 
-  var sharedActions = loop.shared.actions;
   var sharedUtils = loop.shared.utils;
 
   var CALL_REGEXP = /\/c\/([\w\-]+)$/;
   var ROOM_REGEXP = /\/([\w\-]+)$/;
 
   /**
    * Constructor
    *
--- a/browser/extensions/loop/standalone/content/js/webapp.js
+++ b/browser/extensions/loop/standalone/content/js/webapp.js
@@ -6,20 +6,17 @@ var loop = loop || {};
 loop.webapp = (function(_, OT, mozL10n) {
   "use strict";
 
   loop.config = loop.config || {};
   loop.config.serverUrl = loop.config.serverUrl || "http://localhost:5000";
 
   var sharedActions = loop.shared.actions;
   var sharedMixins = loop.shared.mixins;
-  var sharedModels = loop.shared.models;
-  var sharedViews = loop.shared.views;
   var sharedUtils = loop.shared.utils;
-  var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
 
   /**
    * Homepage view.
    */
   var HomeView = React.createClass({displayName: "HomeView",
     render: function() {
       return (
         React.createElement("p", null, mozL10n.get("welcome", { clientShortname: mozL10n.get("clientShortname2") }))
@@ -170,21 +167,20 @@ loop.webapp = (function(_, OT, mozL10n) 
       }
     }
   });
 
   /**
    * App initialization.
    */
   function init() {
-    var standaloneMozLoop = new loop.StandaloneMozLoop({
+    loop.StandaloneMozLoop({
       baseServerUrl: loop.config.serverUrl
     });
 
-    // New flux items.
     var dispatcher = new loop.Dispatcher();
     var sdkDriver = new loop.OTSdkDriver({
       // For the standalone, always request data channels. If they aren't
       // implemented on the client, there won't be a similar message to us, and
       // we won't display the UI.
       constants: {},
       useDataChannels: true,
       dispatcher: dispatcher,
--- a/browser/extensions/loop/standalone/content/js/webapp.jsx
+++ b/browser/extensions/loop/standalone/content/js/webapp.jsx
@@ -6,20 +6,17 @@ var loop = loop || {};
 loop.webapp = (function(_, OT, mozL10n) {
   "use strict";
 
   loop.config = loop.config || {};
   loop.config.serverUrl = loop.config.serverUrl || "http://localhost:5000";
 
   var sharedActions = loop.shared.actions;
   var sharedMixins = loop.shared.mixins;
-  var sharedModels = loop.shared.models;
-  var sharedViews = loop.shared.views;
   var sharedUtils = loop.shared.utils;
-  var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
 
   /**
    * Homepage view.
    */
   var HomeView = React.createClass({
     render: function() {
       return (
         <p>{mozL10n.get("welcome", { clientShortname: mozL10n.get("clientShortname2") })}</p>
@@ -170,21 +167,20 @@ loop.webapp = (function(_, OT, mozL10n) 
       }
     }
   });
 
   /**
    * App initialization.
    */
   function init() {
-    var standaloneMozLoop = new loop.StandaloneMozLoop({
+    loop.StandaloneMozLoop({
       baseServerUrl: loop.config.serverUrl
     });
 
-    // New flux items.
     var dispatcher = new loop.Dispatcher();
     var sdkDriver = new loop.OTSdkDriver({
       // For the standalone, always request data channels. If they aren't
       // implemented on the client, there won't be a similar message to us, and
       // we won't display the UI.
       constants: {},
       useDataChannels: true,
       dispatcher: dispatcher,
--- a/browser/extensions/loop/test/desktop-local/feedbackViews_test.js
+++ b/browser/extensions/loop/test/desktop-local/feedbackViews_test.js
@@ -18,17 +18,17 @@ describe("loop.feedbackViews", function(
   });
 
   afterEach(function() {
     sandbox.restore();
   });
 
   describe("FeedbackView", function() {
     var openURLStub, getLoopPrefStub, feedbackReceivedStub;
-    var fakeURL = "fake.form", mozLoop, view;
+    var fakeURL = "fake.form", view;
 
     function mountTestComponent(props) {
       props = _.extend({
         onAfterFeedbackReceived: feedbackReceivedStub
       }, props);
 
       return TestUtils.renderIntoDocument(
         React.createElement(FeedbackView, props));
--- a/browser/extensions/loop/test/desktop-local/roomStore_test.js
+++ b/browser/extensions/loop/test/desktop-local/roomStore_test.js
@@ -488,33 +488,33 @@ describe("loop.store.RoomStore", functio
 
         store.emailRoomUrl(new sharedActions.EmailRoomUrl({
           roomUrl: "http://invalid",
           from: "conversation"
         }));
 
         sinon.assert.calledOnce(sharedUtils.composeCallUrlEmail);
         sinon.assert.calledWith(sharedUtils.composeCallUrlEmail,
-          "http://invalid", null, undefined, "conversation");
+          "http://invalid", null, undefined);
       });
 
       it("should call composeUrlEmail differently with context", function() {
         sandbox.stub(sharedUtils, "composeCallUrlEmail");
 
         var url = "http://invalid";
         var description = "Hello, is it me you're looking for?";
         store.emailRoomUrl(new sharedActions.EmailRoomUrl({
           roomUrl: url,
           roomDescription: description,
           from: "conversation"
         }));
 
         sinon.assert.calledOnce(sharedUtils.composeCallUrlEmail);
         sinon.assert.calledWithExactly(sharedUtils.composeCallUrlEmail,
-          url, null, description, "conversation");
+          url, null, description);
       });
     });
 
     describe("#shareRoomUrl", function() {
       var socialShareRoomStub;
 
       beforeEach(function() {
         socialShareRoomStub = sinon.stub();
--- a/browser/extensions/loop/test/shared/crypto_test.js
+++ b/browser/extensions/loop/test/shared/crypto_test.js
@@ -1,17 +1,17 @@
 /* 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/. */
 
 describe("loop.crypto", function() {
   "use strict";
 
   var expect = chai.expect;
-  var sandbox, oldCrypto;
+  var sandbox;
 
   beforeEach(function() {
     sandbox = sinon.sandbox.create();
   });
 
   afterEach(function() {
     sandbox.restore();
     loop.crypto.setRootObject(window);
--- a/browser/extensions/loop/test/shared/linkifiedTextView_test.js
+++ b/browser/extensions/loop/test/shared/linkifiedTextView_test.js
@@ -113,17 +113,16 @@ describe("loop.shared.views.LinkifiedTex
 
           TestUtils.Simulate.click(comp.getDOMNode().querySelector("a"));
 
           sinon.assert.calledOnce(linkClickHandler);
         });
 
         it("should cause sendReferrer and suppressTarget props to be ignored",
           function() {
-            var fakeUrl = "http://example.com";
             var linkClickHandler = function() {};
 
             var markup = renderToMarkup("http://example.com", {
               linkClickHandler: linkClickHandler,
               sendReferrer: false,
               suppressTarget: false
             });
 
--- a/browser/extensions/loop/test/shared/mixins_test.js
+++ b/browser/extensions/loop/test/shared/mixins_test.js
@@ -139,17 +139,17 @@ describe("loop.shared.mixins", function(
       comp.closeWindow();
 
       sinon.assert.calledOnce(rootObject.close);
       sinon.assert.calledWithExactly(rootObject.close);
     });
   });
 
   describe("loop.shared.mixins.DocumentVisibilityMixin", function() {
-    var comp, TestComp, onDocumentVisibleStub, onDocumentHiddenStub;
+    var TestComp, onDocumentVisibleStub, onDocumentHiddenStub;
 
     beforeEach(function() {
       onDocumentVisibleStub = sandbox.stub();
       onDocumentHiddenStub = sandbox.stub();
 
       TestComp = React.createClass({
         mixins: [loop.shared.mixins.DocumentVisibilityMixin],
         onDocumentHidden: onDocumentHiddenStub,
@@ -170,27 +170,27 @@ describe("loop.shared.mixins", function(
         }
       });
     }
 
     it("should call onDocumentVisible when document visibility changes to visible",
       function() {
         setupFakeVisibilityEventDispatcher({ target: { hidden: false } });
 
-        comp = TestUtils.renderIntoDocument(React.createElement(TestComp));
+        TestUtils.renderIntoDocument(React.createElement(TestComp));
 
         // Twice, because it's also called when the component was mounted.
         sinon.assert.calledTwice(onDocumentVisibleStub);
       });
 
     it("should call onDocumentVisible when document visibility changes to hidden",
       function() {
         setupFakeVisibilityEventDispatcher({ target: { hidden: true } });
 
-        comp = TestUtils.renderIntoDocument(React.createElement(TestComp));
+        TestUtils.renderIntoDocument(React.createElement(TestComp));
 
         sinon.assert.calledOnce(onDocumentHiddenStub);
       });
   });
 
   describe("loop.shared.mixins.MediaSetupMixin", function() {
     var view;
 
@@ -216,17 +216,17 @@ describe("loop.shared.mixins", function(
         expect(view.getDefaultPublisherConfig({
           publishVideo: true
         }).publishVideo).eql(true);
       });
     });
   });
 
   describe("loop.shared.mixins.AudioMixin", function() {
-    var view, fakeAudio, getAudioBlobStub, TestComp;
+    var TestComp, getAudioBlobStub, fakeAudio;
 
     beforeEach(function() {
       getAudioBlobStub = sinon.stub().returns(
         new Blob([new ArrayBuffer(10)], { type: "audio/ogg" }));
       LoopMochaUtils.stubLoopRequest({
         GetDoNotDisturb: function() { return true; },
         GetAudioBlob: getAudioBlobStub,
         GetLoopPref: sandbox.stub()
@@ -251,35 +251,35 @@ describe("loop.shared.mixins", function(
 
     });
 
     afterEach(function() {
       LoopMochaUtils.restore();
     });
 
     it("should not play a failure sound when doNotDisturb true", function() {
-      view = TestUtils.renderIntoDocument(React.createElement(TestComp));
+      TestUtils.renderIntoDocument(React.createElement(TestComp));
       sinon.assert.notCalled(getAudioBlobStub);
       sinon.assert.notCalled(fakeAudio.play);
     });
 
     it("should play a failure sound, once", function() {
       LoopMochaUtils.stubLoopRequest({
         GetDoNotDisturb: function() { return false; }
       });
-      view = TestUtils.renderIntoDocument(React.createElement(TestComp));
+      TestUtils.renderIntoDocument(React.createElement(TestComp));
       sinon.assert.calledOnce(getAudioBlobStub);
       sinon.assert.calledWithExactly(getAudioBlobStub, "failure");
       sinon.assert.calledOnce(fakeAudio.play);
       expect(fakeAudio.loop).to.equal(false);
     });
   });
 
   describe("loop.shared.mixins.RoomsAudioMixin", function() {
-    var view, fakeAudioMixin, comp;
+    var comp;
 
     function createTestComponent(initialState) {
       var TestComp = React.createClass({
         mixins: [loop.shared.mixins.RoomsAudioMixin],
         render: function() {
           return React.DOM.div();
         },
 
--- a/browser/extensions/loop/test/shared/models_test.js
+++ b/browser/extensions/loop/test/shared/models_test.js
@@ -14,25 +14,23 @@ describe("loop.shared.models", function(
     sandbox = sinon.sandbox.create();
   });
 
   afterEach(function() {
     sandbox.restore();
   });
 
   describe("NotificationCollection", function() {
-    var collection, notifData, testNotif;
+    var collection;
 
     beforeEach(function() {
       collection = new sharedModels.NotificationCollection();
       sandbox.stub(l10n, "get", function(x, y) {
         return "translated:" + x + (y ? ":" + y : "");
       });
-      notifData = { level: "error", message: "plop" };
-      testNotif = new sharedModels.NotificationModel(notifData);
     });
 
     describe("#warn", function() {
       it("should add a warning notification to the stack", function() {
         collection.warn("watch out");
 
         expect(collection).to.have.length.of(1);
         expect(collection.at(0).get("level")).eql("warning");
--- a/browser/extensions/loop/test/shared/otSdkDriver_test.js
+++ b/browser/extensions/loop/test/shared/otSdkDriver_test.js
@@ -746,18 +746,17 @@ describe("loop.OTSdkDriver", function() 
         sinon.assert.calledOnce(driver._publisherChannel.send);
         sinon.assert.calledWithExactly(driver._publisherChannel.send,
           JSON.stringify(message));
       });
     });
   });
 
   describe("Events: general media", function() {
-    var fakeConnection, fakeStream, fakeSubscriberObject,
-      fakeSdkContainerWithVideo, videoElement;
+    var fakeConnection, fakeStream, fakeSubscriberObject, videoElement;
 
     beforeEach(function() {
       fakeConnection = "fakeConnection";
       fakeStream = {
         hasVideo: true,
         videoType: "camera",
         videoDimensions: { width: 1, height: 2 }
       };
@@ -765,20 +764,16 @@ describe("loop.OTSdkDriver", function() 
       fakeSubscriberObject = _.extend({
         "_": {
           getDataChannel: sinon.stub()
         },
         session: { connection: fakeConnection },
         stream: fakeStream
       }, Backbone.Events);
 
-      fakeSdkContainerWithVideo = {
-        querySelector: sinon.stub().returns(videoElement)
-      };
-
       // use a real video element so that these tests correctly reflect
       // test behavior when run in firefox or chrome
       videoElement = document.createElement("video");
 
       driver.connectSession(sessionData);
 
       driver.setupStreamElements(new sharedActions.SetupStreamElements({
         publisherConfig: publisherConfig
@@ -1821,28 +1816,22 @@ describe("loop.OTSdkDriver", function() 
               recvStreams: 0
             }));
         });
       });
     });
   });
 
   describe("Events: screenshare:", function() {
-    var videoElement;
-
     beforeEach(function() {
       driver.connectSession(sessionData);
 
       driver.startScreenShare({
         videoSource: "window"
       });
-
-      // use a real video element so that these tests correctly reflect
-      // code behavior when run in whatever browser
-      videoElement = document.createElement("video");
     });
 
     describe("accessAllowed", function() {
       it("should publish the stream", function() {
         publisher.trigger("accessAllowed", fakeEvent);
 
         sinon.assert.calledOnce(session.publish);
       });
--- a/browser/extensions/loop/test/standalone/standaloneAppStore_test.js
+++ b/browser/extensions/loop/test/standalone/standaloneAppStore_test.js
@@ -1,17 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 describe("loop.store.StandaloneAppStore", function() {
   "use strict";
 
   var expect = chai.expect;
   var sharedActions = loop.shared.actions;
-  var sharedUtils = loop.shared.utils;
   var sandbox, dispatcher;
 
   beforeEach(function() {
     sandbox = sinon.sandbox.create();
     dispatcher = new loop.Dispatcher();
   });
 
   afterEach(function() {
--- a/browser/extensions/loop/test/standalone/standaloneMetricsStore_test.js
+++ b/browser/extensions/loop/test/standalone/standaloneMetricsStore_test.js
@@ -1,16 +1,15 @@
 /* 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/. */
 
 describe("loop.store.StandaloneMetricsStore", function() {
   "use strict";
 
-  var expect = chai.expect;
   var sandbox, dispatcher, store, fakeActiveRoomStore;
 
   var sharedActions = loop.shared.actions;
   var METRICS_GA_CATEGORY = loop.store.METRICS_GA_CATEGORY;
   var METRICS_GA_ACTIONS = loop.store.METRICS_GA_ACTIONS;
   var ROOM_STATES = loop.store.ROOM_STATES;
   var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
 
--- a/browser/extensions/loop/test/standalone/webapp_test.js
+++ b/browser/extensions/loop/test/standalone/webapp_test.js
@@ -68,17 +68,17 @@ describe("loop.webapp", function() {
         new sharedActions.ExtractTokenInfo({
           windowPath: "/c/faketoken",
           windowHash: "#fakeKey"
         }));
     });
   });
 
   describe("WebappRootView", function() {
-    var sdk, conversationModel, client, props, standaloneAppStore;
+    var sdk, standaloneAppStore;
     var activeRoomStore;
 
     function mountTestComponent() {
       return TestUtils.renderIntoDocument(
         React.createElement(
           loop.webapp.WebappRootView, {
             activeRoomStore: activeRoomStore,
             dispatcher: dispatcher,
@@ -155,17 +155,17 @@ describe("loop.webapp", function() {
           React.createElement(loop.webapp.PromoteFirefoxView, {
             isFirefox: true
         }));
 
         expect(comp.getDOMNode()).eql(null);
       });
 
       it("should render when not using Firefox", function() {
-        var comp = TestUtils.renderIntoDocument(
+        TestUtils.renderIntoDocument(
           React.createElement(loop.webapp.PromoteFirefoxView, {
               isFirefox: false
         }));
 
         sinon.assert.calledWith(mozL10nGet, "promote_firefox_hello_heading");
         sinon.assert.calledWith(mozL10nGet, "get_firefox_button");
       });
     });
--- a/browser/extensions/loop/test/xpcshell/test_looppush_initialize.js
+++ b/browser/extensions/loop/test/xpcshell/test_looppush_initialize.js
@@ -116,29 +116,29 @@ add_test(function test_reconnect_no_regi
     },
     dummyCallback
   );
 });
 
 add_test(function test_ping_websocket() {
   let pingReceived = false,
       socketClosed = false;
-  mockWebSocket.defaultMsgHandler = (msg) => {
+  mockWebSocket.defaultMsgHandler = () => {
     pingReceived = true;
     // Do not send a ping response.
   };
   mockWebSocket.close = () => {
     socketClosed = true;
   };
 
   MozLoopPushHandler.shutdown();
   MozLoopPushHandler.initialize({ mockWebSocket: mockWebSocket });
   MozLoopPushHandler.register(
     "test-chan",
-    function(err, url) {
+    function(err) {
       Assert.equal(err, null, "err should be null to indicate success");
       waitForCondition(() => pingReceived).then(() => {
         waitForCondition(() => socketClosed).then(() => {
           run_next_test();
         }, () => {
           do_throw("should have closed the websocket");
         });
       }, () => {
--- a/browser/extensions/loop/test/xpcshell/test_loopservice_registration.js
+++ b/browser/extensions/loop/test/xpcshell/test_loopservice_registration.js
@@ -52,17 +52,17 @@ add_test(function test_register_success(
     }
 
     response.setStatusLine(null, 200, "OK");
     response.processAsync();
     response.finish();
   });
   MozLoopService.promiseRegisteredWithServers().then(() => {
     run_next_test();
-  }, err => {
+  }, () => {
     do_throw("shouldn't error on a successful request");
   });
 });
 
 function run_test() {
   setupFakeLoopServer();
 
   do_register_cleanup(function() {
--- a/browser/extensions/loop/test/xpcshell/test_loopservice_registration_retry.js
+++ b/browser/extensions/loop/test/xpcshell/test_loopservice_registration_retry.js
@@ -30,17 +30,17 @@ add_test(function test_retry_after_faile
     mockPushHandler.registrationPushURL = kEndPointUrl;
 
     yield regError.friendlyDetailsButtonCallback();
     Assert.strictEqual(MozLoopService.errors.size, 0, "Check that the errors are gone");
     let deferredRegistrations = MozLoopServiceInternal.deferredRegistrations;
     yield deferredRegistrations.get(LOOP_SESSION_TYPE.GUEST).then(() => {
       Assert.ok(true, "The retry of registration succeeded");
     },
-    (error) => {
+    () => {
       Assert.ok(false, "The retry of registration should have succeeded");
     });
 
     run_next_test();
   }));
 });
 
 function run_test() {
--- a/browser/extensions/loop/test/xpcshell/test_loopservice_restart.js
+++ b/browser/extensions/loop/test/xpcshell/test_loopservice_restart.js
@@ -18,18 +18,16 @@ const LOOP_FXA_PROFILE_PREF = "loop.fxa_
 const LOOP_CREATED_ROOM_PREF = "loop.createdRoom";
 const LOOP_INITIAL_DELAY_PREF = "loop.initialDelay";
 
 /**
  * This file is to test restart+reauth.
  */
 
 add_task(function* test_initialize_with_no_guest_rooms_and_no_auth_token() {
-  // Set time to be 2 seconds in the past.
-  var nowSeconds = Date.now() / 1000;
   Services.prefs.setBoolPref(LOOP_CREATED_ROOM_PREF, false);
   Services.prefs.clearUserPref(LOOP_FXA_TOKEN_PREF);
 
   yield MozLoopService.initialize().then((msg) => {
     Assert.equal(msg, "registration not needed", "Initialize should not register when the " +
                                                  "URLs are expired and there are no auth tokens");
   }, (error) => {
     Assert.ok(false, error, "should have resolved the promise that initialize returned");
@@ -68,17 +66,17 @@ add_task(function* test_initialize_with_
       error: "Unauthorized",
       message: "Unknown credentials"
     }));
   });
 
   yield MozLoopService.initialize().then(() => {
     Assert.ok(false, "Initializing with an invalid token should reject the promise");
   },
-  (error) => {
+  () => {
     Assert.equal(MozLoopServiceInternal.pushHandler.registrationPushURL, kEndPointUrl, "Push URL should match");
     Assert.equal(Services.prefs.getCharPref(LOOP_FXA_TOKEN_PREF), "",
                  "FXA pref should be cleared if token was invalid");
     Assert.equal(Services.prefs.getCharPref(LOOP_FXA_PROFILE_PREF), "",
                  "FXA profile pref should be cleared if token was invalid");
     Assert.ok(MozLoopServiceInternal.errors.has("login"),
               "Initialization error should have been reported to UI");
     Assert.ok(MozLoopServiceInternal.errors.has("login"));
--- a/browser/extensions/loop/test/xpcshell/test_loopservice_token_save.js
+++ b/browser/extensions/loop/test/xpcshell/test_loopservice_token_save.js
@@ -24,17 +24,17 @@ add_test(function test_registration_retu
       hawkSessionPref = Services.prefs.getCharPref("loop.hawk-session-token");
     } catch (ex) {
       // Do nothing
     }
     Assert.equal(hawkSessionPref, fakeSessionToken, "Should store" +
       " Hawk-Session-Token header contents in loop.hawk-session-token pref");
 
     run_next_test();
-  }, err => {
+  }, () => {
     do_throw("shouldn't error on a successful request");
   });
 });
 
 function run_test() {
   setupFakeLoopServer();
 
   mockPushHandler.registrationPushURL = kEndPointUrl;
--- a/browser/extensions/loop/test/xpcshell/test_loopservice_token_send.js
+++ b/browser/extensions/loop/test/xpcshell/test_loopservice_token_send.js
@@ -23,17 +23,17 @@ add_test(function test_registration_uses
 
     response.setStatusLine(null, 200, "OK");
     response.processAsync();
     response.finish();
   });
 
   MozLoopService.promiseRegisteredWithServers().then(() => {
     run_next_test();
-  }, err => {
+  }, () => {
     do_throw("shouldn't error on a succesful request");
   });
 });
 
 
 function run_test() {
   setupFakeLoopServer();
 
--- a/devtools/client/debugger/test/mochitest/browser.ini
+++ b/devtools/client/debugger/test/mochitest/browser.ini
@@ -10,16 +10,17 @@ support-files =
   addon5.xpi
   code_binary_search.coffee
   code_binary_search.js
   code_binary_search.map
   code_blackboxing_blackboxme.js
   code_blackboxing_one.js
   code_blackboxing_three.js
   code_blackboxing_two.js
+  code_blackboxing_unblackbox.min.js
   code_breakpoints-break-on-last-line-of-script-on-reload.js
   code_breakpoints-other-tabs.js
   code_bug-896139.js
   code_frame-script.js
   code_function-jump-01.js
   code_function-search-01.js
   code_function-search-02.js
   code_function-search-03.js
@@ -46,16 +47,17 @@ support-files =
   code_ugly-8^headers^
   code_WorkerActor.attach-worker1.js
   code_WorkerActor.attach-worker2.js
   code_WorkerActor.attachThread-worker.js
   doc_auto-pretty-print-01.html
   doc_auto-pretty-print-02.html
   doc_binary_search.html
   doc_blackboxing.html
+  doc_blackboxing_unblackbox.html
   doc_breakpoints-break-on-last-line-of-script-on-reload.html
   doc_breakpoints-other-tabs.html
   doc_breakpoints-reload.html
   doc_bug-896139.html
   doc_closures.html
   doc_closure-optimized-out.html
   doc_cmd-break.html
   doc_cmd-dbg.html
@@ -139,16 +141,17 @@ tags = addons
 [browser_dbg_bfcache.js]
 skip-if = e10s || true # bug 1113935
 [browser_dbg_blackboxing-01.js]
 [browser_dbg_blackboxing-02.js]
 [browser_dbg_blackboxing-03.js]
 [browser_dbg_blackboxing-04.js]
 [browser_dbg_blackboxing-05.js]
 [browser_dbg_blackboxing-06.js]
+[browser_dbg_blackboxing-07.js]
 [browser_dbg_breadcrumbs-access.js]
 [browser_dbg_break-in-anon.js]
 [browser_dbg_break-on-next.js]
 [browser_dbg_break-on-next-console.js]
 [browser_dbg_break-on-dom-01.js]
 [browser_dbg_break-on-dom-02.js]
 [browser_dbg_break-on-dom-03.js]
 [browser_dbg_break-on-dom-04.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_blackboxing-07.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test that if we unblackbox a source which has been automatically blackboxed
+ * and then refresh, it is still unblackboxed.
+ */
+
+const TAB_URL = EXAMPLE_URL + "doc_blackboxing_unblackbox.html";
+
+var gTab, gPanel, gDebugger;
+
+function test() {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
+    gTab = aTab;
+    gPanel = aPanel;
+    gDebugger = gPanel.panelWin;
+
+    waitForSourceShown(gPanel, ".min.js")
+      .then(testBlackBoxSource)
+      .then(testBlackBoxReload)
+      .then(() => closeDebuggerAndFinish(gPanel))
+      .then(null, aError => {
+        ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
+      });
+  });
+}
+
+function testBlackBoxSource() {
+  const bbButton = getBlackBoxButton(gPanel);
+  ok(bbButton.checked, "Should be black boxed by default");
+
+  return toggleBlackBoxing(gPanel).then(aSource => {
+    ok(!aSource.isBlackBoxed, "The source should no longer be blackboxed.");
+  });
+}
+
+function testBlackBoxReload() {
+  return reloadActiveTab(gPanel, gDebugger.EVENTS.SOURCE_SHOWN).then(() => {
+    const selectedSource = getSelectedSourceElement(gPanel);
+    ok(!selectedSource.isBlackBoxed, "The source should not be blackboxed.");
+  });
+}
+
+registerCleanupFunction(function() {
+  gTab = null;
+  gPanel = null;
+  gDebugger = null;
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/code_blackboxing_unblackbox.min.js
@@ -0,0 +1,1 @@
+function blackboxme(){one()};function one(){};
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/doc_blackboxing_unblackbox.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Debugger test page</title>
+  <script type="text/javascript" src="code_blackboxing_unblackbox.min.js"></script>
+</head>
+<body>
+  
+</body>
+</html>
\ No newline at end of file
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -307,16 +307,17 @@ devtools.jar:
     skin/images/vview-delete.png (themes/images/vview-delete.png)
     skin/images/vview-delete@2x.png (themes/images/vview-delete@2x.png)
     skin/images/vview-edit.png (themes/images/vview-edit.png)
     skin/images/vview-edit@2x.png (themes/images/vview-edit@2x.png)
     skin/images/vview-lock.png (themes/images/vview-lock.png)
     skin/images/vview-lock@2x.png (themes/images/vview-lock@2x.png)
     skin/images/vview-open-inspector.png (themes/images/vview-open-inspector.png)
     skin/images/vview-open-inspector@2x.png (themes/images/vview-open-inspector@2x.png)
+    skin/images/sort-arrows.svg (themes/images/sort-arrows.svg)
     skin/images/cubic-bezier-swatch.png (themes/images/cubic-bezier-swatch.png)
     skin/images/cubic-bezier-swatch@2x.png (themes/images/cubic-bezier-swatch@2x.png)
     skin/images/undock@2x.png (themes/images/undock@2x.png)
     skin/font-inspector.css (themes/font-inspector.css)
     skin/computedview.css (themes/computedview.css)
     skin/images/arrow-e.png (themes/images/arrow-e.png)
     skin/images/arrow-e@2x.png (themes/images/arrow-e@2x.png)
     skin/projecteditor/projecteditor.css (themes/projecteditor/projecteditor.css)
--- a/devtools/client/netmonitor/netmonitor-view.js
+++ b/devtools/client/netmonitor/netmonitor-view.js
@@ -1001,28 +1001,31 @@ RequestsMenuView.prototype = Heritage.ex
   sortBy: function(aType = "waterfall") {
     let target = $("#requests-menu-" + aType + "-button");
     let headers = document.querySelectorAll(".requests-menu-header-button");
 
     for (let header of headers) {
       if (header != target) {
         header.removeAttribute("sorted");
         header.removeAttribute("tooltiptext");
+        header.parentNode.removeAttribute("active");
       }
     }
 
     let direction = "";
     if (target) {
       if (target.getAttribute("sorted") == "ascending") {
         target.setAttribute("sorted", direction = "descending");
         target.setAttribute("tooltiptext", L10N.getStr("networkMenu.sortedDesc"));
       } else {
         target.setAttribute("sorted", direction = "ascending");
         target.setAttribute("tooltiptext", L10N.getStr("networkMenu.sortedAsc"));
       }
+      // Used to style the next column.
+      target.parentNode.setAttribute("active", "true");
     }
 
     // Sort by whatever was requested.
     switch (aType) {
       case "status":
         if (direction == "ascending") {
           this.sortContents(this._byStatus);
         } else {
@@ -1671,24 +1674,24 @@ RequestsMenuView.prototype = Heritage.ex
         }
 
         let tooltip = L10N.getStr("netmonitor.security.state." + aValue);
         icon.classList.add("security-state-" + aValue);
         icon.setAttribute("tooltiptext", tooltip);
         break;
       }
       case "status": {
-        let node = $(".requests-menu-status", target);
+        let node = $(".requests-menu-status-icon", target);
         node.setAttribute("code", aValue.cached ? "cached" : aValue.status);
         let codeNode = $(".requests-menu-status-code", target);
         codeNode.setAttribute("value", aValue.status);
         break;
       }
       case "statusText": {
-        let node = $(".requests-menu-status-and-method", target);
+        let node = $(".requests-menu-status", target);
         node.setAttribute("tooltiptext", aValue);
         break;
       }
       case "contentSize": {
         let kb = aValue / 1024;
         let size = L10N.numberWithDecimals(kb, CONTENT_SIZE_DECIMALS);
         let node = $(".requests-menu-size", target);
         let text = L10N.getFormatStr("networkMenu.sizeKB", size);
@@ -1845,17 +1848,17 @@ RequestsMenuView.prototype = Heritage.ex
 
   /**
    * Creates the labels displayed on the waterfall header in this container.
    *
    * @param number aScale
    *        The current waterfall scale.
    */
   _showWaterfallDivisionLabels: function(aScale) {
-    let container = $("#requests-menu-waterfall-button");
+    let container = $("#requests-menu-waterfall-label-wrapper");
     let availableWidth = this._waterfallWidth - REQUESTS_WATERFALL_SAFE_BOUNDS;
 
     // Nuke all existing labels.
     while (container.hasChildNodes()) {
       container.firstChild.remove();
     }
 
     // Build new millisecond tick labels...
@@ -1905,16 +1908,18 @@ RequestsMenuView.prototype = Heritage.ex
         node.className = "plain requests-menu-timings-division";
         node.setAttribute("division-scale", divisionScale);
         node.style.transform = translateX;
 
         node.setAttribute("value", text);
         fragment.appendChild(node);
       }
       container.appendChild(fragment);
+
+      container.className = 'requests-menu-waterfall-visible';
     }
   },
 
   /**
    * Creates the background displayed on each waterfall view in this container.
    *
    * @param number aScale
    *        The current waterfall scale.
--- a/devtools/client/netmonitor/netmonitor.xul
+++ b/devtools/client/netmonitor/netmonitor.xul
@@ -96,93 +96,107 @@
       <hbox id="network-table-and-sidebar"
             class="devtools-responsive-container"
             flex="1">
         <vbox id="network-table" flex="1" class="devtools-main-content">
           <toolbar id="requests-menu-toolbar"
                    class="devtools-toolbar"
                    align="center">
             <hbox id="toolbar-labels" flex="1">
-              <hbox id="requests-menu-status-and-method-header-box"
-                    class="requests-menu-header requests-menu-status-and-method"
+              <hbox id="requests-menu-status-header-box"
+                    class="requests-menu-header requests-menu-status"
                     align="center">
                 <button id="requests-menu-status-button"
                         class="requests-menu-header-button requests-menu-status"
                         data-key="status"
-                        label="&netmonitorUI.toolbar.status2;">
+                        label="&netmonitorUI.toolbar.status2;"
+                        flex="1">
                 </button>
+              </hbox>
+              <hbox id="requests-menu-method-header-box"
+                    class="requests-menu-header requests-menu-method"
+                    align="center">
                 <button id="requests-menu-method-button"
                         class="requests-menu-header-button requests-menu-method"
                         data-key="method"
                         label="&netmonitorUI.toolbar.method;"
+                        crop="end"
                         flex="1">
                 </button>
               </hbox>
               <hbox id="requests-menu-icon-and-file-header-box"
                     class="requests-menu-header requests-menu-icon-and-file"
                     align="center">
                 <button id="requests-menu-file-button"
                         class="requests-menu-header-button requests-menu-file"
                         data-key="file"
                         label="&netmonitorUI.toolbar.file;"
+                        crop="end"
                         flex="1">
                 </button>
               </hbox>
               <hbox id="requests-menu-domain-header-box"
                     class="requests-menu-header requests-menu-security-and-domain"
                     align="center">
                 <button id="requests-menu-domain-button"
                         class="requests-menu-header-button requests-menu-security-and-domain"
                         data-key="domain"
                         label="&netmonitorUI.toolbar.domain;"
+                        crop="end"
                         flex="1">
                 </button>
               </hbox>
               <hbox id="requests-menu-type-header-box"
                     class="requests-menu-header requests-menu-type"
                     align="center">
                 <button id="requests-menu-type-button"
                         class="requests-menu-header-button requests-menu-type"
                         data-key="type"
                         label="&netmonitorUI.toolbar.type;"
+                        crop="end"
                         flex="1">
                 </button>
               </hbox>
               <hbox id="requests-menu-transferred-header-box"
                     class="requests-menu-header requests-menu-transferred"
                     align="center">
                 <button id="requests-menu-transferred-button"
                         class="requests-menu-header-button requests-menu-transferred"
                         data-key="transferred"
                         label="&netmonitorUI.toolbar.transferred;"
+                        crop="end"
                         flex="1">
                 </button>
               </hbox>
               <hbox id="requests-menu-size-header-box"
                     class="requests-menu-header requests-menu-size"
                     align="center">
                 <button id="requests-menu-size-button"
                         class="requests-menu-header-button requests-menu-size"
                         data-key="size"
                         label="&netmonitorUI.toolbar.size;"
+                        crop="end"
                         flex="1">
                 </button>
               </hbox>
               <hbox id="requests-menu-waterfall-header-box"
                     class="requests-menu-header requests-menu-waterfall"
                     align="center"
                     flex="1">
                 <button id="requests-menu-waterfall-button"
                         class="requests-menu-header-button requests-menu-waterfall"
                         data-key="waterfall"
                         pack="start"
                         flex="1">
-                  <label id="requests-menu-waterfall-label"
-                         class="plain requests-menu-waterfall"
-                         value="&netmonitorUI.toolbar.waterfall;"/>
+                  <image id="requests-menu-waterfall-image"/>
+                  <box id="requests-menu-waterfall-label-wrapper">
+                    <label id="requests-menu-waterfall-label"
+                           class="plain requests-menu-waterfall"
+                           value="&netmonitorUI.toolbar.waterfall;"/>
+                  </box>
                 </button>
               </hbox>
             </hbox>
             <toolbarbutton id="details-pane-toggle"
                            class="devtools-toolbarbutton"
                            tooltiptext="&netmonitorUI.panesButton.tooltip;"
                            disabled="true"
                            tabindex="0"/>
@@ -204,21 +218,24 @@
                       standalone="true"
                       class="devtools-toolbarbutton"/>
               <label value="&netmonitorUI.perfNotice2;"/>
             </hbox>
           </vbox>
 
           <vbox id="requests-menu-contents" flex="1" context="network-request-popup">
             <hbox id="requests-menu-item-template" hidden="true">
-              <hbox class="requests-menu-subitem requests-menu-status-and-method"
+              <hbox class="requests-menu-subitem requests-menu-status"
                     align="center">
-                <box class="requests-menu-status"/>
+                <box class="requests-menu-status-icon"/>
                 <label class="plain requests-menu-status-code"
                        crop="end"/>
+              </hbox>
+              <hbox class="requests-menu-subitem requests-menu-method-box"
+                    align="center">
                 <label class="plain requests-menu-method"
                        crop="end"
                        flex="1"/>
               </hbox>
               <hbox class="requests-menu-subitem requests-menu-icon-and-file"
                     align="center">
                 <image class="requests-menu-icon" hidden="true"/>
                 <label class="plain requests-menu-file"
@@ -375,17 +392,17 @@
                              readonly="true"/>
                   </hbox>
                   <hbox id="headers-summary-status"
                         class="tabpanel-summary-container"
                         align="center">
                     <label class="plain tabpanel-summary-label"
                            value="&netmonitorUI.summary.status;"/>
                     <box id="headers-summary-status-circle"
-                         class="requests-menu-status"/>
+                         class="requests-menu-status-icon"/>
                     <label id="headers-summary-status-value"
                            class="plain tabpanel-summary-value devtools-monospace"
                            crop="end"
                            flex="1"/>
                     <button id="headers-summary-resend"
                             class="devtools-toolbarbutton"
                             label="&netmonitorUI.summary.editAndResend;"/>
                     <button id="toggle-raw-headers"
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -319,19 +319,19 @@ function verifyRequestItemTarget(aReques
   is(target.querySelector(".requests-menu-domain").getAttribute("value"),
     hostPort, "The displayed domain is correct.");
 
   let domainTooltip = hostPort + (remoteAddress ? " (" + remoteAddress + ")" : "");
   is(target.querySelector(".requests-menu-domain").getAttribute("tooltiptext"),
     domainTooltip, "The tooltip domain is correct.");
 
   if (status !== undefined) {
-    let value = target.querySelector(".requests-menu-status").getAttribute("code");
+    let value = target.querySelector(".requests-menu-status-icon").getAttribute("code");
     let codeValue = target.querySelector(".requests-menu-status-code").getAttribute("value");
-    let tooltip = target.querySelector(".requests-menu-status-and-method").getAttribute("tooltiptext");
+    let tooltip = target.querySelector(".requests-menu-status").getAttribute("tooltiptext");
     info("Displayed status: " + value);
     info("Displayed code: " + codeValue);
     info("Tooltip status: " + tooltip);
     is(value, fromCache ? "cached" : status, "The displayed status is correct.");
     is(codeValue, status, "The displayed status code is correct.");
     is(tooltip, status + " " + statusText, "The tooltip status is correct.");
   }
   if (type !== undefined) {
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/sort-arrows.svg
@@ -0,0 +1,9 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="22" height="11">
+  <g fill="#edf0f1" fill-opacity="0.8">
+    <polygon points="3,5 5.5,8 8,5"/>
+    <polygon points="14,7 16.5,4 19,7"/>
+  </g>
+</svg>
--- a/devtools/client/themes/netmonitor.css
+++ b/devtools/client/themes/netmonitor.css
@@ -39,108 +39,118 @@
 }
 
 /* Network requests table */
 
 #requests-menu-toolbar {
   padding: 0;
 }
 
-.requests-menu-header:first-child,
-.requests-menu-subitem:first-child {
-  -moz-padding-start: 6px;
-}
-
 .requests-menu-subitem {
   padding: 3px;
 }
 
-.requests-menu-header:not(:last-child),
-.requests-menu-subitem:not(:last-child) {
-  -moz-border-end: 1px solid var(--table-splitter-color);
-}
-
 .requests-menu-header-button {
   -moz-appearance: none;
-  background: none;
+  background-color: transparent;
+  border-image: linear-gradient(transparent 15%, var(--theme-splitter-color) 15%, var(--theme-splitter-color) 85%, transparent 85%) 1 1;
+  border-style: solid;
+  border-width: 0;
+  border-inline-start-width: 1px;
   min-width: 1px;
   min-height: 24px;
   margin: 0;
-  border: none;
-  padding: 0;
+  padding-bottom: 2px;
+  padding-inline-start: 13px;
+  padding-top: 2px;
+  text-align: center;
   color: inherit;
   font-weight: inherit !important;
-  transition: background-color 0.1s ease-in-out;
+}
+
+.requests-menu-header:first-child .requests-menu-header-button {
+  border-width: 0;
 }
 
 .requests-menu-header-button:hover {
-  background: rgba(0,0,0,0.10);
+  background-color: rgba(0, 0, 0, 0.1);
 }
 
-.requests-menu-header-button:hover:active {
-  background: rgba(0,0,0,0.25);
+.requests-menu-header-button > .button-box > .button-icon,
+#requests-menu-waterfall-image {
+  display: -moz-box;
+  height: 4px;
+  margin-inline-end: 6px;
+  -moz-box-ordinal-group: 2;
+  width: 7px;
 }
 
-.requests-menu-header-button:not(:active)[sorted] {
-  background: rgba(0,0,0,0.15);
+.requests-menu-header-button[sorted] > .button-box > .button-icon,
+.requests-menu-header-button[sorted] #requests-menu-waterfall-image {
+  list-style-image: url('chrome://devtools/skin/images/sort-arrows.svg');
 }
 
-.requests-menu-header-button:not(:active)[sorted=ascending] {
-  background-image: radial-gradient(farthest-side at center top, hsla(200,100%,70%,.7), hsla(200,100%,70%,0.3));
-  background-size: 100% 1px;
-  background-repeat: no-repeat;
+.requests-menu-header-button[sorted=ascending] > .button-box > .button-icon,
+.requests-menu-header-button[sorted=ascending] #requests-menu-waterfall-image {
+  -moz-image-region: rect(4px, 19px, 7px, 14px);
+}
+
+.requests-menu-header-button[sorted=descending] > .button-box > .button-icon,
+.requests-menu-header-button[sorted=descending] #requests-menu-waterfall-image {
+  -moz-image-region: rect(5px, 8px, 8px, 3px);
 }
 
-.requests-menu-header-button:not(:active)[sorted=descending] {
-  background-image: radial-gradient(farthest-side at center bottom, hsla(200,100%,70%,.7), hsla(200,100%,70%,0.3));
-  background-size: 100% 1px;
-  background-repeat: no-repeat;
-  background-position: bottom;
+.requests-menu-header-button > .button-box > .button-text,
+#requests-menu-waterfall-label-wrapper {
+  -moz-box-flex: 1;
+}
+
+.requests-menu-header-button[sorted],
+.requests-menu-header-button[sorted]:hover {
+  background-color: var(--theme-selection-background);
+  color: var(--theme-selection-color);
+}
+
+.requests-menu-header-button[sorted],
+.requests-menu-header[active] + .requests-menu-header .requests-menu-header-button {
+  border-image: linear-gradient(var(--theme-splitter-color), var(--theme-splitter-color)) 1 1;
 }
 
 /* Network requests table: specific column dimensions */
 
-.requests-menu-status-and-method {
-  width: 12em;
+.requests-menu-status {
+  max-width: 4em;
+  width: 4vw;
 }
 
-.requests-menu-status {
-  width: 20px;
-  height: 10px;
-}
-
+.requests-menu-method-box,
 .requests-menu-method {
+  max-width: 6em;
   text-align: center;
-  font-weight: 600;
+  width: 10vw;
 }
 
 .requests-menu-icon-and-file {
-  width: 20vw;
-  min-width: 4em;
+  width: 22vw;
 }
 
 .requests-menu-icon {
   background: #fff;
   width: calc(1em + 4px);
   height: calc(1em + 4px);
   margin: -4px 0px;
   -moz-margin-end: 4px;
 }
 
 .requests-menu-icon {
   outline: 1px solid var(--table-splitter-color);
 }
 
-.requests-menu-file {
-  text-align: start;
-}
-
 .requests-menu-security-and-domain {
   width: 14vw;
-  min-width: 10em;
 }
 
 .requests-security-state-icon {
   width: 16px;
   height: 16px;
   -moz-margin-end: 4px;
   cursor: pointer;
 }
@@ -160,142 +170,133 @@
 .security-state-broken {
   list-style-image: url(chrome://devtools/skin/images/security-state-broken.svg);
 }
 
 .security-state-local {
   list-style-image: url(chrome://devtools/skin/images/security-state-local.svg);
 }
 
-.requests-menu-type {
+.requests-menu-type,
+.requests-menu-transferred,
+.requests-menu-size {
+  max-width: 8em;
   text-align: center;
-  width: 4em;
-}
-
-.requests-menu-size {
-  text-align: center;
-  width: 8em;
+  width: 8vw;
 }
 
 .requests-menu-transferred {
-  text-align: center;
-  width: 8em;
+  width: 8vw;
 }
 
 /* Network requests table: status codes */
 
-box.requests-menu-status {
+.requests-menu-status-code {
+  -moz-margin-start: 3px !important;
+  width: 3em;
+  -moz-margin-end: -3em !important;
+}
+
+.requests-menu-status-icon {
   background: #fff;
+  height: 10px;
   width: 10px;
   -moz-margin-start: 5px;
   -moz-margin-end: 5px;
   border-radius: 10px;
   transition: box-shadow 0.5s ease-in-out;
 }
 
-label.requests-menu-status-code {
-  -moz-margin-start: 3px !important;
-  width: 3em;
-  -moz-margin-end: -3em !important;
+.requests-menu-status-icon:not([code]) {
+  background-color: var(--theme-content-color2);
 }
 
-box.requests-menu-status:not([code]) {
-  background-color: var(--theme-highlight-red);
-  border-radius: 0; /* squares */
-}
-
-box.requests-menu-status[code="cached"] {
+.requests-menu-status-icon[code="cached"] {
   border: 2px solid var(--theme-content-color2);
   background-color: transparent;
 }
 
-box.requests-menu-status[code^="1"] {
+.requests-menu-status-icon[code^="1"] {
   background-color: var(---theme-highlight-blue);
 }
 
-box.requests-menu-status[code^="2"] {
+.requests-menu-status-icon[code^="2"] {
   background-color: var(--theme-highlight-green);
 }
 
 /* 3xx are triangles */
-box.requests-menu-status[code^="3"] {
+.requests-menu-status-icon[code^="3"] {
   background-color: transparent;
   width: 0;
   height: 0;
   border-left: 5px solid transparent;
   border-right: 5px solid transparent;
   border-bottom: 10px solid var(--theme-highlight-lightorange);
   border-radius: 0;
 }
 
 /* 4xx and 5xx are squares - error codes */
-box.requests-menu-status[code^="4"] {
-  background-color: var(--theme-highlight-red);
+.requests-menu-status-icon[code^="4"] {
+ background-color: var(--theme-highlight-red);
   border-radius: 0; /* squares */
 }
 
-box.requests-menu-status[code^="5"] {
+.requests-menu-status-icon[code^="5"] {
   background-color: var(--theme-highlight-pink);
   border-radius: 0;
   transform: rotate(45deg);
 }
 
 /* Network requests table: waterfall header */
 
-#requests-menu-waterfall-label {
-  -moz-padding-start: 8px;
-  -moz-padding-end: 8px;
+.requests-menu-waterfall {
+  padding-inline-start: 0;
+}
+
+#requests-menu-waterfall-label:not(.requests-menu-waterfall-visible) {
+  padding-inline-start: 13px;
 }
 
 .requests-menu-timings-division {
   width: 100px;
   padding-top: 2px;
-  -moz-padding-start: 4px;
+  padding-inline-start: 4px;
   font-size: 75%;
   pointer-events: none;
+  box-sizing: border-box;
+  text-align: start;
+}
+
+.requests-menu-timings-division:first-child {
+  width: 98px; /* Substract 2px for borders */
 }
 
 .requests-menu-timings-division:not(:first-child) {
-  -moz-border-start: 1px dotted;
-  -moz-margin-start: -100px !important; /* Don't affect layout. */
+  border-inline-start: 1px dashed;
+  margin-inline-start: -100px !important; /* Don't affect layout. */
 }
 
 .requests-menu-timings-division:-moz-locale-dir(ltr) {
   transform-origin: left center;
 }
 
 .requests-menu-timings-division:-moz-locale-dir(rtl) {
   transform-origin: right center;
 }
 
-.theme-dark .requests-menu-timings-division[division-scale=millisecond] {
-  -moz-border-start-color: var(--theme-selection-color) !important;
-}
-
-.theme-light .requests-menu-timings-division[division-scale=millisecond] {
-  -moz-border-start-color: var(--theme-body-color-alt) !important;
-}
-
-.theme-dark .requests-menu-timings-division[division-scale=second] {
-  -moz-border-start-color: var(--theme-selection-color) !important;
-  font-weight: 600;
+.theme-dark .requests-menu-timings-division {
+  border-inline-start-color: #5a6169 !important;
 }
 
-.theme-light .requests-menu-timings-division[division-scale=second] {
-  -moz-border-start-color: var(--theme-body-color-alt) !important;
-  font-weight: 600;
+.theme-light .requests-menu-timings-division {
+  border-inline-start-color: #585959 !important;
 }
 
-.theme-dark .requests-menu-timings-division[division-scale=minute] {
-  -moz-border-start-color: var(--theme-selection-color) !important;
-  font-weight: 600;
-}
-
-.theme-light .requests-menu-timings-division[division-scale=minute] {
-  -moz-border-start-color: var(--theme-body-color-alt) !important;
+.requests-menu-timings-division[division-scale=second],
+.requests-menu-timings-division[division-scale=minute] {
   font-weight: 600;
 }
 
 /* Network requests table: waterfall items */
 
 .requests-menu-subitem.requests-menu-waterfall {
   -moz-padding-start: 0px;
   -moz-padding-end: 4px;
@@ -779,46 +780,54 @@ box.requests-menu-status[code^="5"] {
 
 /* Responsive sidebar */
 @media (max-width: 700px) {
   #requests-menu-toolbar {
     height: 22px;
   }
 
   .requests-menu-header-button {
-    min-height: 20px;
+    min-height: 22px;
+    padding-left: 8px;
   }
 
   #details-pane {
     margin: 0 !important;
     /* To prevent all the margin hacks to hide the sidebar. */
   }
 
-  .requests-menu-status-and-method {
-    width: 16vw;
+  .requests-menu-status {
+    width: 4vw;
+  }
+
+  #requests-menu-status-button {
+    min-width: 26px;
+  }
+
+  .requests-menu-method,
+  .requests-menu-method-box {
+    max-width: none;
+    width: 14vw;
   }
 
   .requests-menu-icon-and-file {
     width: 30vw;
   }
 
   .requests-menu-security-and-domain {
-    width: 30vw;
+    width: 28vw;
   }
 
-  .requests-menu-type {
-    width: 8vw;
+  .requests-menu-type,
+  .requests-menu-transferred {
+    width: 12vw;
   }
 
   .requests-menu-size {
     width: 16vw;
-    border-width: 0 !important;
-    box-shadow: none !important;
-    /* The "Timeline" header is not visible anymore, and thus the
-       right border and box-shadow of "Size" column should be hidden. */
   }
 }
 
 /* Platform overrides (copied in from the old platform specific files) */
 %ifdef XP_WIN
 .requests-menu-header-button > .button-box {
   padding: 0;
 }
@@ -846,27 +855,15 @@ box.requests-menu-status[code^="5"] {
 #headers-summary-resend {
   padding: 4px;
 }
 
 #toggle-raw-headers {
   padding: 4px;
 }
 
-.requests-menu-status-and-method {
-  width: 9em;
-}
-
-.requests-menu-security-and-domain {
-  width: 16vw;
-}
-
-.requests-menu-size {
-  width: 6em;
-}
-
 /* Responsive sidebar */
 @media (max-width: 700px) {
   .requests-menu-header-button {
     font-size: 85%;
   }
 }
 %endif
--- a/devtools/server/actors/utils/TabSources.js
+++ b/devtools/server/actors/utils/TabSources.js
@@ -29,16 +29,17 @@ function TabSources(threadActor, allowSo
   this._autoBlackBox = true;
   this._anonSourceMapId = 1;
   this.allowSource = source => {
     return !isHiddenSource(source) && allowSourceFn(source);
   }
 
   this.blackBoxedSources = new Set();
   this.prettyPrintedSources = new Map();
+  this.neverAutoBlackBoxSources = new Set();
 
   // generated Debugger.Source -> promise of SourceMapConsumer
   this._sourceMaps = new Map();
   // sourceMapURL -> promise of SourceMapConsumer
   this._sourceMapCache = Object.create(null);
   // Debugger.Source -> SourceActor
   this._sourceActors = new Map();
   // url -> SourceActor
@@ -164,18 +165,22 @@ TabSources.prototype = {
     var id = sourceActorStore.getReusableActorId(source, originalUrl);
     if (id) {
       actor.actorID = id;
     }
 
     this._thread.threadLifetimePool.addActor(actor);
     sourceActorStore.setReusableActorId(source, originalUrl, actor.actorID);
 
-    if (this._autoBlackBox && this._isMinifiedURL(actor.url)) {
+    if (this._autoBlackBox &&
+        !this.neverAutoBlackBoxSources.has(actor.url) &&
+        this._isMinifiedURL(actor.url)) {
+
       this.blackBox(actor.url);
+      this.neverAutoBlackBoxSources.add(actor.url);
     }
 
     if (source) {
       this._sourceActors.set(source, actor);
     }
     else {
       this._sourceMappedSourceActors[originalUrl] = actor;
     }
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -219,17 +219,17 @@
 <!ENTITY pref_cookies_menu "Cookies">
 <!ENTITY pref_cookies_accept_all "Enabled">
 <!ENTITY pref_cookies_not_accept_foreign "Enabled, excluding 3rd party">
 <!ENTITY pref_cookies_disabled "Disabled">
 
 <!ENTITY pref_tap_to_load_images_title2 "Show images">
 <!ENTITY pref_tap_to_load_images_enabled "Always">
 <!ENTITY pref_tap_to_load_images_data "Only over Wi-Fi">
-<!ENTITY pref_tap_to_load_images_disabled "Never">
+<!ENTITY pref_tap_to_load_images_disabled2 "Blocked">
 
 <!ENTITY pref_tracking_protection_title "Tracking protection">
 <!ENTITY pref_tracking_protection_summary3 "Enabled in Private Browsing">
 <!ENTITY pref_donottrack_title "Do not track">
 <!ENTITY pref_donottrack_summary "&brandShortName; will tell sites that you do not want to be tracked">
 
 <!ENTITY pref_tracking_protection_enabled "Enabled">
 <!ENTITY pref_tracking_protection_enabled_pb "Enabled in Private Browsing">
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -1,16 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 DIRS += ['locales']
-SPHINX_TREES['fennec'] = 'docs'
 
 include('android-services.mozbuild')
 
 thirdparty_source_dir = TOPSRCDIR + '/mobile/android/thirdparty/'
 
 constants_jar = add_java_jar('constants')
 constants_jar.sources = ['java/org/mozilla/gecko/' + x for x in [
     'adjust/AdjustHelperInterface.java',
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6c3bda221e198bc1e35d9c2393bb2728bd02cca6
GIT binary patch
literal 544
zc$@(s0^j|KP)<h;3K|Lk000e1NJLTq002z@001}$1^@s6xaM`j0005!Nkl<ZcmeI)
zQ8&au3<cmOv-<+z|Nlh*Z?*x@bI(be*?`!4p>2VDvdzGfAs-v+W&64rhG7^+c6<Wa
zcNQ+?5#vafEmVT%<u4*S02V~DI7%EsaQpp;X(YpK4{)ZF1fk%Z4u3D>JAwmeJ)O83
zmLs@@Cq$Y%mLKY}F@R_eki2d4H$ewY0Y;sU(;x3D=&;HDh;UBVLHG4{n#^FS59oK^
zH$n{#P<z`d!Y<xKA**N?I$&)A2aqpm39KyM=KUPtjg#6C(V$-Q&<uePY7Xq;`u=h#
zmb2siQ-D^$oL!1&;NtIsVW$?#3hH={LcQ+b(yk!@V3pAvI1fz1gJ9Za4p^%w2A}r>
zUKf{^9l8L9Q&0i0a;G({3F?&?8h`<uOuB46*;dRN>VRca_?qTl%XX~Ouy%={E#WqR
zs~5ip?ZUv|iXRuPg$DtA{(hZ_K`;rx6-PrbO#dM8v2ed&{8}^u*IRUh3u)QFAZwlC
z@vjPgfZ|IIYy^#(Xacu>r^P*Tg8)8Y*+Br?<RIW**hr?+FzRfp#;+%i#t@BYL?ar}
z7@`r4Xhb6#Lo}ihjc7z;h(<J`?E>29AD2qJo&=gz#7f{<2F+$Zzy`L}f}j8B*WZEm
i&$}yCC;!F77I_4Wt6%*x>?G^}0000<MNUMnLSTZ;8TMHK
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0076357d7b5c4762ee085197675f4eafd6e69928
GIT binary patch
literal 661
zc%17D@N?(olHy`uVBq!ia0vp^X+Z47!3-qp@-NB)si**-5LX5ofOj9i0?FjpyKe(2
znUWyCU<M8$ab_+)MiwR+Ha%-~MN=LD5l%5lIcZgGqth{NRSXP_=R92;Ln>~)y?M8&
zSwVpH0n3`LM~;ZF2G0Iof3~R1Y3`W^@z>S%K8P`{DZaKh(Z;1X`N@PylRizaOi%g!
zSAO=UsOmj-x97O$iE%o7T+Nar#pR*k_gyAjWe#shLy}K`!-coLpSLOcGWV~LPxn$}
zVQcYMi5Iov;udlgJ{QZ#)co#xM}%PSglDP_2WN&hJotC(xP-F!qy7gfCJx1XhD#QB
z@g0uOUt4-^W$O>+e+!-~Jk?-%K5-|jnufzZ2}TnuM#-5v++7b0lq@2}QUjiOc%4nm
zD(YKdeDJ~R>Z1{S$-U(p*aO*84UFy|)#6*c=6&<Vh38K6q-LZnnzrhZ!PH4x7i<ii
zYq2={<*mNMC2J>dotG>%W#g({1v9*t>bx>3T&5A=<`G_M+x~L*DbGeLSHVPs%`w3<
zCmo&=;{LoYOHfVOP2zT0%(CpYf=5ye+2*&UnH9`vT-MevoS4D9A$`WpsfS|>P2Whp
zb!a(gb-Rpz+17}ck;`81^trz_sm-|ElHc2BUGM5|30mnTb_WyYADj}ijHS7EUg8Eu
z8#e0=2Ryd&FHT7knmpr(ike}krw@o(f70gV!;e|dSkjieE6&)tefiz?jc(8ND?IIA
bet%`|5P2!huyPqFxiNUU`njxgN@xNA?*H%;
--- a/mobile/android/base/resources/values-v11/themes.xml
+++ b/mobile/android/base/resources/values-v11/themes.xml
@@ -36,16 +36,17 @@
         GeckoAppBase from res/values/themes.xml on API 11+ devices.
     -->
     <style name="GeckoAppBase" parent="Gecko">
         <item name="android:actionButtonStyle">@style/GeckoActionBar.Button</item>
         <item name="android:actionModeCopyDrawable">@drawable/ab_copy</item>
         <item name="android:actionModeCutDrawable">@drawable/ab_cut</item>
         <item name="android:actionModePasteDrawable">@drawable/ab_paste</item>
         <item name="android:listViewStyle">@style/Widget.ListView</item>
+        <item name="android:panelBackground">@drawable/menu_panel_bg</item>
         <item name="android:spinnerDropDownItemStyle">@style/Widget.DropDownItem.Spinner</item>
         <item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
         <item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>
         <item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
         <item name="menuItemSecondaryActionBarStyle">@style/Widget.MenuItemSecondaryActionBar</item>
         <item name="tabGridLayoutViewStyle">@style/Widget.TabsGridLayout</item>
     </style>
 
--- a/mobile/android/base/resources/values-v14/themes.xml
+++ b/mobile/android/base/resources/values-v14/themes.xml
@@ -12,16 +12,17 @@
     <style name="GeckoAppBase" parent="Gecko">
         <item name="android:actionButtonStyle">@style/GeckoActionBar.Button</item>
         <item name="android:actionModeCopyDrawable">@drawable/ab_copy</item>
         <item name="android:actionModeCutDrawable">@drawable/ab_cut</item>
         <item name="android:actionModePasteDrawable">@drawable/ab_paste</item>
         <item name="android:actionModeSelectAllDrawable">@drawable/ab_select_all</item>
         <item name="android:actionModeStyle">@style/GeckoActionBar</item>
         <item name="android:listViewStyle">@style/Widget.ListView</item>
+        <item name="android:panelBackground">@drawable/menu_panel_bg</item>
         <item name="android:spinnerDropDownItemStyle">@style/Widget.DropDownItem.Spinner</item>
         <item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
         <item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>
         <item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
         <item name="menuItemSecondaryActionBarStyle">@style/Widget.MenuItemSecondaryActionBar</item>
     </style>
 
 </resources>
--- a/mobile/android/base/resources/values-v21/themes.xml
+++ b/mobile/android/base/resources/values-v21/themes.xml
@@ -37,16 +37,17 @@
 
     <style name="ActionBar.GeckoPreferences" parent="@android:style/Widget.Material.ActionBar.Solid">
         <item name="android:titleTextStyle">@style/ActionBarTitleTextStyle</item>
     </style>
 
     <style name="GeckoAppBase" parent="Gecko">
         <item name="android:actionButtonStyle">@style/GeckoActionBar.Button</item>
         <item name="android:listViewStyle">@style/Widget.ListView</item>
+        <item name="android:panelBackground">@drawable/menu_panel_bg</item>
         <item name="android:spinnerDropDownItemStyle">@style/Widget.DropDownItem.Spinner</item>
         <item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
         <item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>
         <item name="menuItemDefaultStyle">@style/Widget.MenuItemDefault</item>
         <item name="menuItemSecondaryActionBarStyle">@style/Widget.MenuItemSecondaryActionBar</item>
         <item name="tabGridLayoutViewStyle">@style/Widget.TabsGridLayout</item>
     </style>
 
--- a/mobile/android/base/resources/values/arrays.xml
+++ b/mobile/android/base/resources/values/arrays.xml
@@ -165,16 +165,16 @@
         <item>1</item>
         <item>20</item>
         <item>21</item>
     </integer-array>
     <!-- browser.image_blocking -->
     <string-array name="pref_browser_image_blocking_entries">
         <item>@string/pref_tap_to_load_images_enabled</item>
         <item>@string/pref_tap_to_load_images_data</item>
-        <item>@string/pref_tap_to_load_images_disabled</item>
+        <item>@string/pref_tap_to_load_images_disabled2</item>
     </string-array>
     <string-array name="pref_browser_image_blocking_values">
         <item>1</item> <!-- Always -->
         <item>2</item> <!-- Wifi-only -->
-        <item>0</item> <!-- Never -->
+        <item>0</item> <!-- Blocked -->
     </string-array>
 </resources>
--- a/mobile/android/base/resources/values/themes.xml
+++ b/mobile/android/base/resources/values/themes.xml
@@ -7,16 +7,23 @@
 
     <!--
         Base application theme. This could be overridden by GeckoBaseTheme
         in other res/values-XXX/themes.xml.
     -->
     <style name="GeckoBase" parent="Theme.AppCompat.Light.DarkActionBar">
         <item name="windowNoTitle">true</item>
         <item name="android:windowContentOverlay">@null</item>
+
+        <!-- Gingerbread "More" menu background color; AppCompat sets this to
+             transparent by default: http://stackoverflow.com/a/31777488.
+             This color is set anecdotally to make all text colors, which change
+             by device, visible. Standard colors are #8D8D8D & #C8C8C8 (disabled)
+             and #000000 has also been seen. -->
+        <item name="android:panelBackground">@color/text_and_tabs_tray_grey</item>
     </style>
 
     <style name="GeckoDialogBase" parent="@android:style/Theme.Dialog">
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
     <style name="GeckoTitleDialogBase" parent="@android:style/Theme.Dialog" />
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -207,17 +207,17 @@
   <string name="pref_cookies_menu">&pref_cookies_menu;</string>
   <string name="pref_cookies_accept_all">&pref_cookies_accept_all;</string>
   <string name="pref_cookies_not_accept_foreign">&pref_cookies_not_accept_foreign;</string>
   <string name="pref_cookies_disabled">&pref_cookies_disabled;</string>
 
   <string name="pref_tap_to_load_images_title2">&pref_tap_to_load_images_title2;</string>
   <string name="pref_tap_to_load_images_enabled">&pref_tap_to_load_images_enabled;</string>
   <string name="pref_tap_to_load_images_data">&pref_tap_to_load_images_data;</string>
-  <string name="pref_tap_to_load_images_disabled">&pref_tap_to_load_images_disabled;</string>
+  <string name="pref_tap_to_load_images_disabled2">&pref_tap_to_load_images_disabled2;</string>
 
   <string name="pref_tracking_protection_title">&pref_tracking_protection_title;</string>
   <string name="pref_tracking_protection_summary">&pref_tracking_protection_summary3;</string>
   <string name="pref_donottrack_title">&pref_donottrack_title;</string>
   <string name="pref_donottrack_summary">&pref_donottrack_summary;</string>
 
   <string name="pref_tracking_protection_enabled">&pref_tracking_protection_enabled;</string>
   <string name="pref_tracking_protection_enabled_pb">&pref_tracking_protection_enabled_pb;</string>
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/Makefile
@@ -0,0 +1,177 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  xml        to make Docutils-native XML files"
+	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/FirefoxforAndroid.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/FirefoxforAndroid.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/FirefoxforAndroid"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/FirefoxforAndroid"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through platex and dvipdfmx..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+	@echo
+	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+	@echo
+	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
rename from mobile/android/base/docs/adjust.rst
rename to mobile/android/docs/adjust.rst
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/conf.py
@@ -0,0 +1,258 @@
+# -*- coding: utf-8 -*-
+#
+# Firefox for Android documentation build configuration file, created by
+# sphinx-quickstart on Fri Dec  4 22:51:57 2015.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Firefox for Android'
+copyright = u'2015, mobile team'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.0'
+# The full version, including alpha/beta/rc tags.
+release = '1.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'FirefoxforAndroiddoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+  ('index', 'FirefoxforAndroid.tex', u'Firefox for Android Documentation',
+   u'mobile team', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'firefoxforandroid', u'Firefox for Android Documentation',
+     [u'mobile team'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'FirefoxforAndroid', u'Firefox for Android Documentation',
+   u'mobile team', 'FirefoxforAndroid', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
rename from mobile/android/base/docs/gradle.rst
rename to mobile/android/docs/gradle.rst
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/index.rst
@@ -0,0 +1,25 @@
+.. Firefox for Android documentation master file, created by
+   sphinx-quickstart on Fri Dec  4 22:51:57 2015.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to Firefox for Android's documentation!
+===============================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   localeswitching
+   uitelemetry
+   adjust
+   gradle
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
rename from mobile/android/base/docs/localeswitching.rst
rename to mobile/android/docs/localeswitching.rst
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/make.bat
@@ -0,0 +1,242 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+	set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  texinfo    to make Texinfo files
+	echo.  gettext    to make PO message catalogs
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  xml        to make Docutils-native XML files
+	echo.  pseudoxml  to make pseudoxml-XML files for display purposes
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 (
+	echo.
+	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+	echo.installed, then set the SPHINXBUILD environment variable to point
+	echo.to the full path of the 'sphinx-build' executable. Alternatively you
+	echo.may add the Sphinx directory to PATH.
+	echo.
+	echo.If you don't have Sphinx installed, grab it from
+	echo.http://sphinx-doc.org/
+	exit /b 1
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\FirefoxforAndroid.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\FirefoxforAndroid.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "latexpdf" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	cd %BUILDDIR%/latex
+	make all-pdf
+	cd %BUILDDIR%/..
+	echo.
+	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "latexpdfja" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	cd %BUILDDIR%/latex
+	make all-pdf-ja
+	cd %BUILDDIR%/..
+	echo.
+	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "texinfo" (
+	%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+	goto end
+)
+
+if "%1" == "gettext" (
+	%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+if "%1" == "xml" (
+	%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The XML files are in %BUILDDIR%/xml.
+	goto end
+)
+
+if "%1" == "pseudoxml" (
+	%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+	goto end
+)
+
+:end
rename from mobile/android/base/docs/uitelemetry.rst
rename to mobile/android/docs/uitelemetry.rst
--- a/mobile/android/moz.build
+++ b/mobile/android/moz.build
@@ -27,8 +27,10 @@ DIRS += [
     'extensions',
 ]
 
 DIRS += ['../../xulrunner/tools/redit']
 
 TEST_DIRS += [
     'tests',
 ]
+
+SPHINX_TREES['fennec'] = 'docs'