Merge b2g-inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 03 Nov 2014 19:31:47 -0800
changeset 238099 5dde8ea48fef69066cc66f1d4b620071537ea274
parent 238093 1782c0c6aee79fa037bb64040d5b6d3ca6182be1 (diff)
parent 238098 9247b220e5958fbf692141e90328bddba7bdda61 (current diff)
child 238111 ecaab80d7b3fda79b1288dbeb0b69044697ee11c
child 238145 6d6f30a6125752e09b1853d1ae4835c9895d49df
child 238157 53c21e42a5ec54547914ca1d8df7645fa9f43980
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
5dde8ea48fef / 36.0a1 / 20141104030202 / files
nightly linux64
5dde8ea48fef / 36.0a1 / 20141104030202 / files
nightly mac
5dde8ea48fef / 36.0a1 / 20141104030202 / files
nightly win32
5dde8ea48fef / 36.0a1 / 20141104030202 / files
nightly win64
5dde8ea48fef / 36.0a1 / 20141104030202 / 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 b2g-inbound to m-c a=merge
CLOBBER
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,13 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
+<<<<<<< local
+Bug 1092813 needs a CLOBBER
+=======
 Bug 1056337 - Change the default compiler on B2G ICS to gcc 4.8.
+>>>>>>> other
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -45,9 +45,9 @@ FINAL_LIBRARY = 'xul'
 
 if CONFIG['MOZ_ENABLE_GTK']:
     CFLAGS += CONFIG['TK_CFLAGS']
     CXXFLAGS += CONFIG['TK_CFLAGS']
 
 if CONFIG['MOZ_ENABLE_DBUS']:
     CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
 
-    include('/ipc/chromium/chromium-config.mozbuild')
+include('/ipc/chromium/chromium-config.mozbuild')
--- a/browser/app/macbuild/Contents/MacOS-files.in
+++ b/browser/app/macbuild/Contents/MacOS-files.in
@@ -1,10 +1,9 @@
 /*.app/***
 /*.dylib
 /certutil
 /firefox-bin
 /gtest/***
 /pk12util
 /ssltunnel
-/webapprt-stub
 /xpcshell
 /XUL
--- a/browser/components/loop/LoopRooms.jsm
+++ b/browser/components/loop/LoopRooms.jsm
@@ -101,16 +101,21 @@ const checkForParticipantsUpdate = funct
  *
  * Each method that is a member of this class requires the last argument to be a
  * callback Function. MozLoopAPI will cause things to break if this invariant is
  * violated. You'll notice this as well in the documentation for each method.
  */
 let LoopRoomsInternal = {
   rooms: new Map(),
 
+  get sessionType() {
+    return MozLoopService.userProfile ? LOOP_SESSION_TYPE.FXA :
+                                        LOOP_SESSION_TYPE.GUEST;
+  },
+
   /**
    * Fetch a list of rooms that the currently registered user is a member of.
    *
    * @param {String}   [version] If set, we will fetch a list of changed rooms since
    *                             `version`. Optional.
    * @param {Function} callback  Function that will be invoked once the operation
    *                             finished. The first argument passed will be an
    *                             `Error` object or `null`. The second argument will
@@ -126,20 +131,18 @@ let LoopRoomsInternal = {
       yield MozLoopService.promiseRegisteredWithServers();
 
       if (!gDirty) {
         callback(null, [...this.rooms.values()]);
         return;
       }
 
       // Fetch the rooms from the server.
-      let sessionType = MozLoopService.userProfile ? LOOP_SESSION_TYPE.FXA :
-                        LOOP_SESSION_TYPE.GUEST;
       let url = "/rooms" + (version ? "?version=" + encodeURIComponent(version) : "");
-      let response = yield MozLoopService.hawkRequest(sessionType, url, "GET");
+      let response = yield MozLoopService.hawkRequest(this.sessionType, url, "GET");
       let roomsList = JSON.parse(response.body);
       if (!Array.isArray(roomsList)) {
         throw new Error("Missing array of rooms in response.");
       }
 
       for (let room of roomsList) {
         // See if we already have this room in our cache.
         let orig = this.rooms.get(room.roomToken);
@@ -183,19 +186,17 @@ let LoopRoomsInternal = {
     let needsUpdate = !("participants" in room);
     if (!gDirty && !needsUpdate) {
       // Dirty flag is not set AND the necessary data is available, so we can
       // simply return the room.
       callback(null, room);
       return;
     }
 
-    let sessionType = MozLoopService.userProfile ? LOOP_SESSION_TYPE.FXA :
-                      LOOP_SESSION_TYPE.GUEST;
-    MozLoopService.hawkRequest(sessionType, "/rooms/" + encodeURIComponent(roomToken), "GET")
+    MozLoopService.hawkRequest(this.sessionType, "/rooms/" + encodeURIComponent(roomToken), "GET")
       .then(response => {
         let data = JSON.parse(response.body);
 
         room.roomToken = roomToken;
         checkForParticipantsUpdate(room, data);
         extend(room, data);
 
         // Remove the `currSize` for posterity.
@@ -222,20 +223,17 @@ let LoopRoomsInternal = {
    */
   create: function(room, callback) {
     if (!("roomName" in room) || !("expiresIn" in room) ||
         !("roomOwner" in room) || !("maxSize" in room)) {
       callback(new Error("Missing required property to create a room"));
       return;
     }
 
-    let sessionType = MozLoopService.userProfile ? LOOP_SESSION_TYPE.FXA :
-                      LOOP_SESSION_TYPE.GUEST;
-
-    MozLoopService.hawkRequest(sessionType, "/rooms", "POST", room)
+    MozLoopService.hawkRequest(this.sessionType, "/rooms", "POST", room)
       .then(response => {
         let data = JSON.parse(response.body);
         extend(room, data);
         // Do not keep this value - it is a request to the server.
         delete room.expiresIn;
         this.rooms.set(room.roomToken, room);
 
         eventEmitter.emit("add", room);
@@ -248,16 +246,38 @@ let LoopRoomsInternal = {
       roomToken: roomToken,
       type: "room"
     };
 
     MozLoopService.openChatWindow(windowData);
   },
 
   /**
+   * Deletes a room.
+   *
+   * @param {String}   roomToken The room token.
+   * @param {Function} callback  Function that will be invoked once the operation
+   *                             finished. The first argument passed will be an
+   *                             `Error` object or `null`.
+   */
+  delete: function(roomToken, callback) {
+    // XXX bug 1092954: Before deleting a room, the client should check room
+    //     membership and forceDisconnect() all current participants.
+    let room = this.rooms.get(roomToken);
+    let url = "/rooms/" + encodeURIComponent(roomToken);
+    MozLoopService.hawkRequest(this.sessionType, url, "DELETE")
+      .then(response => {
+        this.rooms.delete(roomToken);
+        eventEmitter.emit("delete", room);
+        callback(null, room);
+      }, error => callback(error)).catch(error => callback(error));
+  },
+
+
+  /**
    * Callback used to indicate changes to rooms data on the LoopServer.
    *
    * @param {String} version   Version number assigned to this change set.
    * @param {String} channelID Notification channel identifier.
    */
   onNotification: function(version, channelID) {
     gDirty = true;
     this.getAll(version, () => {});
@@ -268,17 +288,17 @@ Object.freeze(LoopRoomsInternal);
 /**
  * Public Loop Rooms API.
  *
  * LoopRooms implements the EventEmitter interface by exposing three methods -
  * `on`, `once` and `off` - to subscribe to events.
  * At this point the following events may be subscribed to:
  *  - 'add[:{room-id}]':    A new room object was successfully added to the data
  *                          store.
- *  - 'remove[:{room-id}]': A room was successfully removed from the data store.
+ *  - 'delete[:{room-id}]': A room was successfully removed from the data store.
  *  - 'update[:{room-id}]': A room object was successfully updated with changed
  *                          properties in the data store.
  *  - 'joined[:{room-id}]': A participant joined a room.
  *  - 'left[:{room-id}]':   A participant left a room.
  *
  * See the internal code for the API documentation.
  */
 this.LoopRooms = {
@@ -293,16 +313,20 @@ this.LoopRooms = {
   create: function(options, callback) {
     return LoopRoomsInternal.create(options, callback);
   },
 
   open: function(roomToken) {
     return LoopRoomsInternal.open(roomToken);
   },
 
+  delete: function(roomToken, callback) {
+    return LoopRoomsInternal.delete(roomToken, callback);
+  },
+
   promise: function(method, ...params) {
     return new Promise((resolve, reject) => {
       this[method](...params, (error, result) => {
         if (error) {
           reject(error);
         } else {
           resolve(result);
         }
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -462,70 +462,82 @@ loop.panel = (function(_, mozL10n) {
     }
   });
 
   /**
    * Room list entry.
    */
   var RoomEntry = React.createClass({displayName: 'RoomEntry',
     propTypes: {
-      openRoom: React.PropTypes.func.isRequired,
-      room:     React.PropTypes.instanceOf(loop.store.Room).isRequired
+      dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
+      room:       React.PropTypes.instanceOf(loop.store.Room).isRequired
     },
 
     getInitialState: function() {
       return { urlCopied: false };
     },
 
     shouldComponentUpdate: function(nextProps, nextState) {
       return (nextProps.room.ctime > this.props.room.ctime) ||
         (nextState.urlCopied !== this.state.urlCopied);
     },
 
-    handleClickRoom: function(event) {
+    handleClickRoomUrl: function(event) {
       event.preventDefault();
-      this.props.openRoom(this.props.room);
+      this.props.dispatcher.dispatch(new sharedActions.OpenRoom({
+        roomToken: this.props.room.roomToken
+      }));
     },
 
     handleCopyButtonClick: function(event) {
       event.preventDefault();
       navigator.mozLoop.copyString(this.props.room.roomUrl);
       this.setState({urlCopied: true});
     },
 
+    handleDeleteButtonClick: function(event) {
+      event.preventDefault();
+      // XXX We should prompt end user for confirmation; see bug 1092953.
+      this.props.dispatcher.dispatch(new sharedActions.DeleteRoom({
+        roomToken: this.props.room.roomToken
+      }));
+    },
+
     handleMouseLeave: function(event) {
       this.setState({urlCopied: false});
     },
 
     _isActive: function() {
       // XXX bug 1074679 will implement this properly
       return this.props.room.participants.length > 0;
     },
 
     render: function() {
       var room = this.props.room;
       var roomClasses = React.addons.classSet({
         "room-entry": true,
         "room-active": this._isActive()
       });
       var copyButtonClasses = React.addons.classSet({
-        'copy-link': true,
-        'checked': this.state.urlCopied
+        "copy-link": true,
+        "checked": this.state.urlCopied
       });
 
       return (
         React.DOM.div({className: roomClasses, onMouseLeave: this.handleMouseLeave}, 
           React.DOM.h2(null, 
             React.DOM.span({className: "room-notification"}), 
-              room.roomName, 
+            room.roomName, 
             React.DOM.button({className: copyButtonClasses, 
-              onClick: this.handleCopyButtonClick})
+              onClick: this.handleCopyButtonClick}), 
+            React.DOM.button({className: "delete-link", 
+              onClick: this.handleDeleteButtonClick})
           ), 
           React.DOM.p(null, 
-            React.DOM.a({ref: "room", href: "#", onClick: this.handleClickRoom}, 
+            React.DOM.a({href: "#", onClick: this.handleClickRoomUrl}, 
               room.roomUrl
             )
           )
         )
       );
     }
   });
 
@@ -576,34 +588,32 @@ loop.panel = (function(_, mozL10n) {
 
     handleCreateButtonClick: function() {
       this.props.dispatcher.dispatch(new sharedActions.CreateRoom({
         nameTemplate: mozL10n.get("rooms_default_room_name_template"),
         roomOwner: this.props.userDisplayName
       }));
     },
 
-    openRoom: function(room) {
-      this.props.dispatcher.dispatch(new sharedActions.OpenRoom({
-        roomToken: room.roomToken
-      }));
-    },
-
     render: function() {
       if (this.state.error) {
         // XXX Better end user reporting of errors.
         console.error("RoomList error", this.state.error);
       }
 
       return (
         React.DOM.div({className: "rooms"}, 
           React.DOM.h1(null, this._getListHeading()), 
           React.DOM.div({className: "room-list"}, 
             this.state.rooms.map(function(room, i) {
-              return RoomEntry({key: i, room: room, openRoom: this.openRoom});
+              return RoomEntry({
+                key: room.roomToken, 
+                dispatcher: this.props.dispatcher, 
+                room: room}
+              );
             }, this)
           ), 
           React.DOM.p(null, 
             React.DOM.button({className: "btn btn-info", 
                     onClick: this.handleCreateButtonClick, 
                     disabled: this._hasPendingOperation()}, 
               mozL10n.get("rooms_new_room_button_label")
             )
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -462,70 +462,82 @@ loop.panel = (function(_, mozL10n) {
     }
   });
 
   /**
    * Room list entry.
    */
   var RoomEntry = React.createClass({
     propTypes: {
-      openRoom: React.PropTypes.func.isRequired,
-      room:     React.PropTypes.instanceOf(loop.store.Room).isRequired
+      dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
+      room:       React.PropTypes.instanceOf(loop.store.Room).isRequired
     },
 
     getInitialState: function() {
       return { urlCopied: false };
     },
 
     shouldComponentUpdate: function(nextProps, nextState) {
       return (nextProps.room.ctime > this.props.room.ctime) ||
         (nextState.urlCopied !== this.state.urlCopied);
     },
 
-    handleClickRoom: function(event) {
+    handleClickRoomUrl: function(event) {
       event.preventDefault();
-      this.props.openRoom(this.props.room);
+      this.props.dispatcher.dispatch(new sharedActions.OpenRoom({
+        roomToken: this.props.room.roomToken
+      }));
     },
 
     handleCopyButtonClick: function(event) {
       event.preventDefault();
       navigator.mozLoop.copyString(this.props.room.roomUrl);
       this.setState({urlCopied: true});
     },
 
+    handleDeleteButtonClick: function(event) {
+      event.preventDefault();
+      // XXX We should prompt end user for confirmation; see bug 1092953.
+      this.props.dispatcher.dispatch(new sharedActions.DeleteRoom({
+        roomToken: this.props.room.roomToken
+      }));
+    },
+
     handleMouseLeave: function(event) {
       this.setState({urlCopied: false});
     },
 
     _isActive: function() {
       // XXX bug 1074679 will implement this properly
       return this.props.room.participants.length > 0;
     },
 
     render: function() {
       var room = this.props.room;
       var roomClasses = React.addons.classSet({
         "room-entry": true,
         "room-active": this._isActive()
       });
       var copyButtonClasses = React.addons.classSet({
-        'copy-link': true,
-        'checked': this.state.urlCopied
+        "copy-link": true,
+        "checked": this.state.urlCopied
       });
 
       return (
         <div className={roomClasses} onMouseLeave={this.handleMouseLeave}>
           <h2>
             <span className="room-notification" />
-              {room.roomName}
+            {room.roomName}
             <button className={copyButtonClasses}
-              onClick={this.handleCopyButtonClick}/>
+              onClick={this.handleCopyButtonClick} />
+            <button className="delete-link"
+              onClick={this.handleDeleteButtonClick} />
           </h2>
           <p>
-            <a ref="room" href="#" onClick={this.handleClickRoom}>
+            <a href="#" onClick={this.handleClickRoomUrl}>
               {room.roomUrl}
             </a>
           </p>
         </div>
       );
     }
   });
 
@@ -576,34 +588,32 @@ loop.panel = (function(_, mozL10n) {
 
     handleCreateButtonClick: function() {
       this.props.dispatcher.dispatch(new sharedActions.CreateRoom({
         nameTemplate: mozL10n.get("rooms_default_room_name_template"),
         roomOwner: this.props.userDisplayName
       }));
     },
 
-    openRoom: function(room) {
-      this.props.dispatcher.dispatch(new sharedActions.OpenRoom({
-        roomToken: room.roomToken
-      }));
-    },
-
     render: function() {
       if (this.state.error) {
         // XXX Better end user reporting of errors.
         console.error("RoomList error", this.state.error);
       }
 
       return (
         <div className="rooms">
           <h1>{this._getListHeading()}</h1>
           <div className="room-list">{
             this.state.rooms.map(function(room, i) {
-              return <RoomEntry key={i} room={room} openRoom={this.openRoom} />;
+              return <RoomEntry
+                key={room.roomToken}
+                dispatcher={this.props.dispatcher}
+                room={room}
+              />;
             }, this)
           }</div>
           <p>
             <button className="btn btn-info"
                     onClick={this.handleCreateButtonClick}
                     disabled={this._hasPendingOperation()}>
               {mozL10n.get("rooms_new_room_button_label")}
             </button>
--- a/browser/components/loop/content/shared/css/panel.css
+++ b/browser/components/loop/content/shared/css/panel.css
@@ -217,47 +217,58 @@ body {
   text-decoration: none;
 }
 
 .room-list > .room-entry > p > a:hover {
   opacity: 1;
   text-decoration: underline;
 }
 
-.room-list > .room-entry > h2 > .copy-link {
+@keyframes drop-and-fade-in {
+  0%   {opacity: 0; top: -15px;}
+  25%  {opacity: 0; top: -15px;}
+  100% {opacity: 1; top: 0px;}
+}
+
+.room-list > .room-entry > h2 > button {
   display: inline-block;
+  position: relative;
   width: 24px;
   height: 24px;
   border: none;
-  margin: .1em .5em; /* relative to _this_ line's font, not the document's */
+  margin: .1em .1em .1em .5em; /* relative to _this_ line's font, not the document's */
   background-color: transparent;  /* override browser default for button tags */
+  top: -15px;
 }
 
-@keyframes drop-and-fade-in {
-  from { opacity: 0; transform: translateY(-10px); }
-  to { opacity: 100; transform: translateY(0); }
+.room-list > .room-entry:hover > h2 > button {
+  animation: drop-and-fade-in 0.250s;
+  animation-fill-mode: forwards;
+  cursor: pointer;
 }
 
 .room-list > .room-entry:hover > h2 > .copy-link {
-  background: transparent url(../img/svg/copy-16x16.svg);
-  cursor: pointer;
-  animation: drop-and-fade-in 0.4s;
-  animation-fill-mode: forwards;
+  background-image: url(../img/icons-16x16.svg#copy);
+}
+
+.room-list > .room-entry:hover > h2 > .delete-link {
+  background-image: url(../img/icons-16x16.svg#trash);
 }
 
 /* scale this up to 1.1x and then back to the original size */
 @keyframes pulse {
   0%, 100% { transform: scale(1.0); }
-  50% { transform: scale(1.1); }
+  50%      { transform: scale(1.1); }
 }
 
 .room-list > .room-entry > h2 > .copy-link.checked {
-  background: transparent url(../img/svg/checkmark-16x16.svg);
-  animation: pulse .250s;
+  background: transparent url(../img/icons-16x16.svg#checkmark);
+  animation: pulse .150s;
   animation-timing-function: ease-in-out;
+  top: 0px;
 }
 
 .room-list > .room-entry > h2 {
   display: inline-block;
 }
 
 /* keep the various room-entry row pieces aligned with each other */
 .room-list > .room-entry > h2 > button,
--- a/browser/components/loop/content/shared/img/icons-16x16.svg
+++ b/browser/components/loop/content/shared/img/icons-16x16.svg
@@ -82,41 +82,75 @@ use[id$="-red"] {
     c-0.511,0.511-1.339,0.511-1.85,0c-0.511-0.511-0.511-1.339,0-1.85c0.511-0.511,1.339-0.511,1.85,0
     C4.733,2.823,4.733,3.652,4.222,4.163z"/>
   <path id="unblock-shape" fill-rule="evenodd" clip-rule="evenodd" d="M8,16c-4.418,0-8-3.582-8-8c0-4.418,3.582-8,8-8
     c4.418,0,8,3.582,8,8C16,12.418,12.418,16,8,16z M8,2.442C4.911,2.442,2.408,4.931,2.408,8c0,3.069,2.504,5.557,5.592,5.557
     S13.592,11.069,13.592,8C13.592,4.931,11.089,2.442,8,2.442z"/>
   <path id="video-shape" fill-rule="evenodd" clip-rule="evenodd" d="M14.9,3.129l-3.476,3.073V3.873c0-0.877-0.663-1.587-1.482-1.587
     H1.482C0.663,2.286,0,2.996,0,3.873v8.254c0,0.877,0.663,1.587,1.482,1.587h8.461c0.818,0,1.482-0.711,1.482-1.587V9.762
     l3.476,3.073c0.3,0.321,0.714,0.416,1.1,0.331V2.798C15.614,2.713,15.2,2.808,14.9,3.129z"/>
+  <g id="copy-shape">
+    <circle fill-rule="evenodd" clip-rule="evenodd" fill="#0096DD" cx="8" cy="8" r="8"/>
+    <path fill-rule="evenodd" clip-rule="evenodd" fill="none"
+          stroke="#FFFFFF" stroke-width="0.75" stroke-miterlimit="10"
+          d="M10.815,6.286H7.556c-0.164,0-0.296,0.128-0.296,0.286v5.143C7.259,11.872,7.392,12,7.556,12h4.148
+             C11.867,12,12,11.872,12,11.714V7.429L10.815,6.286z
+             M8.741,6.275V5.143L7.556,4H7.528C6.509,4,4.593,4,4.593,4H4.296
+             C4.133,4,4,4.128,4,4.286v5.143c0,0.158,0.133,0.286,0.296,0.286H7.25V6.561c0-0.158,0.133-0.286,0.296-0.286H8.741z"/>
+    <polygon fill-rule="evenodd" clip-rule="evenodd"
+             fill="#FFFFFF" points="10.222,8 10.222,6.857 11.407,8"/>
+    <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
+             points="6.963,5.714 6.963,4.571 8.148,5.714"/>
+  </g>
+  <g id="checkmark-shape">
+    <circle fill-rule="evenodd" clip-rule="evenodd" fill="#0096DD" cx="8"
+            cy="8" r="8"/>
+    <path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
+          d="M7.236,12L12,5.007L10.956,4L7.224,9.465l-2.14-2.326L4,8.146L7.236,12z"/>
+  </g>
+  <g id="trash-shape">
+    <circle fill-rule="evenodd" clip-rule="evenodd" fill="#D74345" cx="8" cy="8" r="8"/>
+    <path fill="#FFFFFF" d="M12,5.79c0-0.742-0.537-1.344-1.2-1.344h-0.583V4.121c0-0.713-0.516-1.29-1.152-1.29h-2.13
+      c-0.636,0-1.152,0.578-1.152,1.29v0.324H5.2C4.537,4.446,4,5.048,4,5.79v0.898h0.687l0.508,5.438
+      c0.054,0.585,0.543,1.044,1.114,1.044h3.38c0.57,0,1.06-0.458,1.114-1.043l0.509-5.439H12V5.79z M6.407,4.264V4.165
+      c0-0.375,0.271-0.678,0.606-0.678h1.974c0.334,0,0.606,0.304,0.606,0.678v0.099c0,0.063-0.01,0.123-0.025,0.181H6.432
+      C6.417,4.387,6.407,4.328,6.407,4.264z M10.057,12.056c-0.019,0.197-0.188,0.363-0.368,0.363h-3.38
+      c-0.182,0-0.35-0.166-0.368-0.363L5.44,6.687h5.12L10.057,12.056z"/>
+    <rect x="7.75" y="7.542" fill="#FFFFFF" width="0.5" height="4"/>
+    <polyline fill="#FFFFFF" points="9.25,7.542 8.75,7.542 8.75,11.542 9.25,11.542  "/>
+    <rect x="6.75" y="7.542" fill="#FFFFFF" width="0.5" height="4"/>
+  </g>
 </defs>
 <use id="audio"               xlink:href="#audio-shape"/>
 <use id="audio-hover"         xlink:href="#audio-shape"/>
 <use id="audio-active"        xlink:href="#audio-shape"/>
 <use id="block"               xlink:href="#block-shape"/>
 <use id="block-red"           xlink:href="#block-shape"/>
 <use id="block-hover"         xlink:href="#block-shape"/>
 <use id="block-active"        xlink:href="#block-shape"/>
 <use id="contacts"            xlink:href="#contacts-shape"/>
 <use id="contacts-hover"      xlink:href="#contacts-shape"/>
 <use id="contacts-active"     xlink:href="#contacts-shape"/>
+<use id="copy"                xlink:href="#copy-shape"/>
+<use id="checkmark"           xlink:href="#checkmark-shape"/>
 <use id="google"              xlink:href="#google-shape"/>
 <use id="google-hover"        xlink:href="#google-shape"/>
 <use id="google-active"       xlink:href="#google-shape"/>
 <use id="history"             xlink:href="#history-shape"/>
 <use id="history-hover"       xlink:href="#history-shape"/>
 <use id="history-active"      xlink:href="#history-shape"/>
 <use id="precall"             xlink:href="#precall-shape"/>
 <use id="precall-hover"       xlink:href="#precall-shape"/>
 <use id="precall-active"      xlink:href="#precall-shape"/>
 <use id="settings"            xlink:href="#settings-shape"/>
 <use id="settings-hover"      xlink:href="#settings-shape"/>
 <use id="settings-active"     xlink:href="#settings-shape"/>
 <use id="tag"                 xlink:href="#tag-shape"/>
 <use id="tag-hover"           xlink:href="#tag-shape"/>
 <use id="tag-active"          xlink:href="#tag-shape"/>
+<use id="trash"               xlink:href="#trash-shape"/>
 <use id="unblock"             xlink:href="#unblock-shape"/>
 <use id="unblock-hover"       xlink:href="#unblock-shape"/>
 <use id="unblock-active"      xlink:href="#unblock-shape"/>
 <use id="video"               xlink:href="#video-shape"/>
 <use id="video-hover"         xlink:href="#video-shape"/>
 <use id="video-active"        xlink:href="#video-shape"/>
 </svg>
deleted file mode 100644
--- a/browser/components/loop/content/shared/img/svg/checkmark-16x16.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
-     xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-     viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
-  <circle fill-rule="evenodd" clip-rule="evenodd" fill="#0096DD" cx="8"
-          cy="8" r="8"/>
-  <path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
-        d="M7.236,12L12,5.007L10.956,4L7.224,9.465l-2.14-2.326L4,8.146L7.236,12z"/>
-</svg>
deleted file mode 100644
--- a/browser/components/loop/content/shared/img/svg/copy-16x16.svg
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
-     xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-     viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
-  <circle fill-rule="evenodd" clip-rule="evenodd" fill="#0096DD" cx="8" cy="8"
-           r="8"/>
-  <g>
-    <g>
-      <g>
-        <path fill-rule="evenodd" clip-rule="evenodd" fill="none"
-              stroke="#FFFFFF" stroke-width="0.75" stroke-miterlimit="10"
-              d="M10.815,6.286H7.556c-0.164,0-0.296,0.128-0.296,0.286v5.143C7.259,11.872,7.392,12,7.556,12h4.148
-                 C11.867,12,12,11.872,12,11.714V7.429L10.815,6.286z
-                 M8.741,6.275V5.143L7.556,4H7.528C6.509,4,4.593,4,4.593,4H4.296
-                 C4.133,4,4,4.128,4,4.286v5.143c0,0.158,0.133,0.286,0.296,0.286H7.25V6.561c0-0.158,0.133-0.286,0.296-0.286H8.741z"/>
-      </g>
-    </g>
-    <g>
-      <polygon fill-rule="evenodd" clip-rule="evenodd"
-               fill="#FFFFFF" points="10.222,8 10.222,6.857 11.407,8"/>
-    </g>
-    <g>
-      <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
-               points="6.963,5.714 6.963,4.571 8.148,5.714"/>
-    </g>
-  </g>
-</svg>
--- a/browser/components/loop/content/shared/js/actions.js
+++ b/browser/components/loop/content/shared/js/actions.js
@@ -154,16 +154,32 @@ loop.shared.actions = (function() {
      * Rooms creation error.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     CreateRoomError: Action.define("createRoomError", {
       error: Error
     }),
 
     /**
+     * Deletes a room.
+     * XXX: should move to some roomActions module - refs bug 1079284
+     */
+    DeleteRoom: Action.define("deleteRoom", {
+      roomToken: String
+    }),
+
+    /**
+     * Room deletion error.
+     * XXX: should move to some roomActions module - refs bug 1079284
+     */
+    DeleteRoomError: Action.define("deleteRoomError", {
+      error: Error
+    }),
+
+    /**
      * Retrieves room list.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     GetAllRooms: Action.define("getAllRooms", {
     }),
 
     /**
      * An error occured while trying to fetch the room list.
--- a/browser/components/loop/content/shared/js/roomListStore.js
+++ b/browser/components/loop/content/shared/js/roomListStore.js
@@ -66,16 +66,18 @@ loop.store = loop.store || {};
     if (!options.mozLoop) {
       throw new Error("Missing option mozLoop");
     }
     this._mozLoop = options.mozLoop;
 
     this._dispatcher.register(this, [
       "createRoom",
       "createRoomError",
+      "deleteRoom",
+      "deleteRoomError",
       "getAllRooms",
       "getAllRoomsError",
       "openRoom",
       "updateRoomList"
     ]);
   }
 
   RoomListStore.prototype = _.extend({
@@ -134,17 +136,17 @@ loop.store = loop.store || {};
 
     /**
      * Registers mozLoop.rooms events.
      */
     startListeningToRoomEvents: function() {
       // Rooms event registration
       this._mozLoop.rooms.on("add", this._onRoomAdded.bind(this));
       this._mozLoop.rooms.on("update", this._onRoomUpdated.bind(this));
-      this._mozLoop.rooms.on("remove", this._onRoomRemoved.bind(this));
+      this._mozLoop.rooms.on("delete", this._onRoomRemoved.bind(this));
     },
 
     /**
      * Local proxy helper to dispatch an action.
      *
      * @param {Action} action The action to dispatch.
      */
     _dispatchAction: function(action) {
@@ -176,30 +178,29 @@ loop.store = loop.store || {};
         roomList: this._storeState.rooms.map(function(room) {
           return room.roomToken === updatedRoomData.roomToken ?
                  updatedRoomData : room;
         })
       }));
     },
 
     /**
-     * Executed when a room is removed.
+     * Executed when a room is deleted.
      *
      * @param {String} eventName       The event name (unused).
      * @param {Object} removedRoomData The removed room data.
      */
     _onRoomRemoved: function(eventName, removedRoomData) {
       this._dispatchAction(new sharedActions.UpdateRoomList({
         roomList: this._storeState.rooms.filter(function(room) {
           return room.roomToken !== removedRoomData.roomToken;
         })
       }));
     },
 
-
     /**
      * Maps and sorts the raw room list received from the mozLoop API.
      *
      * @param  {Array} rawRoomList Raw room list.
      * @return {Array}
      */
     _processRoomList: function(rawRoomList) {
       if (!rawRoomList) {
@@ -262,17 +263,17 @@ loop.store = loop.store || {};
         roomOwner: actionData.roomOwner,
         maxSize:   this.maxRoomCreationSize,
         expiresIn: this.defaultExpiresIn
       };
 
       this._mozLoop.rooms.create(roomCreationData, function(err) {
         this.setStoreState({pendingCreation: false});
         if (err) {
-         this._dispatchAction(new sharedActions.CreateRoomError({error: err}));
+          this._dispatchAction(new sharedActions.CreateRoomError({error: err}));
         }
       }.bind(this));
     },
 
     /**
      * Executed when a room creation error occurs.
      *
      * @param {sharedActions.CreateRoomError} actionData The action data.
@@ -280,16 +281,38 @@ loop.store = loop.store || {};
     createRoomError: function(actionData) {
       this.setStoreState({
         error: actionData.error,
         pendingCreation: false
       });
     },
 
     /**
+     * Creates a new room.
+     *
+     * @param {sharedActions.DeleteRoom} actionData The action data.
+     */
+    deleteRoom: function(actionData) {
+      this._mozLoop.rooms.delete(actionData.roomToken, function(err) {
+        if (err) {
+         this._dispatchAction(new sharedActions.DeleteRoomError({error: err}));
+        }
+      }.bind(this));
+    },
+
+    /**
+     * Executed when a room deletion error occurs.
+     *
+     * @param {sharedActions.DeleteRoomError} actionData The action data.
+     */
+    deleteRoomError: function(actionData) {
+      this.setStoreState({error: actionData.error});
+    },
+
+    /**
      * Gather the list of all available rooms from the MozLoop API.
      */
     getAllRooms: function() {
       this.setStoreState({pendingInitialRetrieval: true});
       this._mozLoop.rooms.getAll(null, function(err, rawRoomList) {
         var action;
 
         this.setStoreState({pendingInitialRetrieval: false});
--- a/browser/components/loop/jar.mn
+++ b/browser/components/loop/jar.mn
@@ -44,18 +44,16 @@ browser.jar:
   content/browser/loop/shared/img/video-inverse-14x14.png       (content/shared/img/video-inverse-14x14.png)
   content/browser/loop/shared/img/video-inverse-14x14@2x.png    (content/shared/img/video-inverse-14x14@2x.png)
   content/browser/loop/shared/img/dropdown-inverse.png          (content/shared/img/dropdown-inverse.png)
   content/browser/loop/shared/img/dropdown-inverse@2x.png       (content/shared/img/dropdown-inverse@2x.png)
   content/browser/loop/shared/img/svg/glyph-settings-16x16.svg  (content/shared/img/svg/glyph-settings-16x16.svg)
   content/browser/loop/shared/img/svg/glyph-account-16x16.svg   (content/shared/img/svg/glyph-account-16x16.svg)
   content/browser/loop/shared/img/svg/glyph-signin-16x16.svg    (content/shared/img/svg/glyph-signin-16x16.svg)
   content/browser/loop/shared/img/svg/glyph-signout-16x16.svg   (content/shared/img/svg/glyph-signout-16x16.svg)
-  content/browser/loop/shared/img/svg/copy-16x16.svg            (content/shared/img/svg/copy-16x16.svg)
-  content/browser/loop/shared/img/svg/checkmark-16x16.svg       (content/shared/img/svg/checkmark-16x16.svg)
   content/browser/loop/shared/img/audio-call-avatar.svg         (content/shared/img/audio-call-avatar.svg)
   content/browser/loop/shared/img/beta-ribbon.svg               (content/shared/img/beta-ribbon.svg)
   content/browser/loop/shared/img/icons-10x10.svg               (content/shared/img/icons-10x10.svg)
   content/browser/loop/shared/img/icons-14x14.svg               (content/shared/img/icons-14x14.svg)
   content/browser/loop/shared/img/icons-16x16.svg               (content/shared/img/icons-16x16.svg)
 
   # Shared scripts
   content/browser/loop/shared/js/actions.js           (content/shared/js/actions.js)
--- a/browser/components/loop/test/desktop-local/panel_test.js
+++ b/browser/components/loop/test/desktop-local/panel_test.js
@@ -634,79 +634,131 @@ describe("loop.panel", function() {
         sinon.assert.calledOnce(notifications.errorL10n);
         sinon.assert.calledWithExactly(notifications.errorL10n,
                                        "unable_retrieve_url");
       });
     });
   });
 
   describe("loop.panel.RoomEntry", function() {
-    var buttonNode, roomData, roomEntry, roomStore, dispatcher;
+    var dispatcher, roomData;
 
     beforeEach(function() {
       dispatcher = new loop.Dispatcher();
       roomData = {
         roomToken: "QzBbvGmIZWU",
         roomUrl: "http://sample/QzBbvGmIZWU",
         roomName: "Second Room Name",
         maxSize: 2,
         participants: [
           { displayName: "Alexis", account: "alexis@example.com",
             roomConnectionId: "2a1787a6-4a73-43b5-ae3e-906ec1e763cb" },
           { displayName: "Adam",
             roomConnectionId: "781f012b-f1ea-4ce1-9105-7cfc36fb4ec7" }
         ],
         ctime: 1405517418
       };
-      roomStore = new loop.store.Room(roomData);
-      roomEntry = mountRoomEntry();
-      buttonNode = roomEntry.getDOMNode().querySelector("button.copy-link");
-    });
-
-    function mountRoomEntry() {
-      return TestUtils.renderIntoDocument(loop.panel.RoomEntry({
-        openRoom: sandbox.stub(),
-        room: roomStore
-      }));
-    }
-
-    it("should not display copy-link button by default", function() {
-      expect(buttonNode).to.not.equal(null);
     });
 
-    it("should copy the URL when the click event fires", function() {
-      TestUtils.Simulate.click(buttonNode);
+    function mountRoomEntry(props) {
+      return TestUtils.renderIntoDocument(loop.panel.RoomEntry(props));
+    }
+
+    describe("Copy button", function() {
+      var roomEntry, copyButton;
+
+      beforeEach(function() {
+        roomEntry = mountRoomEntry({
+          dispatcher: dispatcher,
+          deleteRoom: sandbox.stub(),
+          room: new loop.store.Room(roomData)
+        });
+        copyButton = roomEntry.getDOMNode().querySelector("button.copy-link");
+      });
+
+      it("should not display a copy button by default", function() {
+        expect(copyButton).to.not.equal(null);
+      });
+
+      it("should copy the URL when the click event fires", function() {
+        TestUtils.Simulate.click(copyButton);
 
-      sinon.assert.calledOnce(navigator.mozLoop.copyString);
-      sinon.assert.calledWithExactly(navigator.mozLoop.copyString,
-        roomData.roomUrl);
-    });
+        sinon.assert.calledOnce(navigator.mozLoop.copyString);
+        sinon.assert.calledWithExactly(navigator.mozLoop.copyString,
+          roomData.roomUrl);
+      });
+
+      it("should set state.urlCopied when the click event fires", function() {
+        TestUtils.Simulate.click(copyButton);
+
+        expect(roomEntry.state.urlCopied).to.equal(true);
+      });
 
-    it("should set state.urlCopied when the click event fires", function() {
-      TestUtils.Simulate.click(buttonNode);
+      it("should switch to displaying a check icon when the URL has been copied",
+        function() {
+          TestUtils.Simulate.click(copyButton);
+
+          expect(copyButton.classList.contains("checked")).eql(true);
+        });
 
-      expect(roomEntry.state.urlCopied).to.equal(true);
+      it("should not display a check icon after mouse leaves the entry",
+        function() {
+          var roomNode = roomEntry.getDOMNode();
+          TestUtils.Simulate.click(copyButton);
+
+          TestUtils.SimulateNative.mouseOut(roomNode);
+
+          expect(copyButton.classList.contains("checked")).eql(false);
+        });
     });
 
-    it("should switch to displaying a check icon when the URL has been copied",
-      function() {
-        TestUtils.Simulate.click(buttonNode);
+    describe("Delete button click", function() {
+      var roomEntry, deleteButton;
 
-        expect(buttonNode.classList.contains("checked")).eql(true);
+      beforeEach(function() {
+        roomEntry = mountRoomEntry({
+          dispatcher: dispatcher,
+          room: new loop.store.Room(roomData)
+        });
+        deleteButton = roomEntry.getDOMNode().querySelector("button.delete-link");
+      });
+
+      it("should not display a delete button by default", function() {
+        expect(deleteButton).to.not.equal(null);
       });
 
-    it("should not display a check icon after mouse leaves the entry",
-      function() {
-        var roomNode = roomEntry.getDOMNode();
-        TestUtils.Simulate.click(buttonNode);
+      it("should call the delete function when clicked", function() {
+        sandbox.stub(dispatcher, "dispatch");
+
+        TestUtils.Simulate.click(deleteButton);
+
+        sinon.assert.calledOnce(dispatcher.dispatch);
+        sinon.assert.calledWithExactly(dispatcher.dispatch,
+          new sharedActions.DeleteRoom({roomToken: roomData.roomToken}));
+      });
+    });
+
+    describe("Room URL click", function() {
+      var roomEntry;
 
-        TestUtils.SimulateNative.mouseOut(roomNode);
+      it("should dispatch an OpenRoom action", function() {
+        sandbox.stub(dispatcher, "dispatch");
+        roomEntry = mountRoomEntry({
+          dispatcher: dispatcher,
+          room: new loop.store.Room(roomData)
+        });
+        var urlLink = roomEntry.getDOMNode().querySelector("p > a");
 
-        expect(buttonNode.classList.contains("checked")).eql(false);
+        TestUtils.Simulate.click(urlLink);
+
+        sinon.assert.calledOnce(dispatcher.dispatch);
+        sinon.assert.calledWithExactly(dispatcher.dispatch,
+          new sharedActions.OpenRoom({roomToken: roomData.roomToken}));
       });
+    });
   });
 
   describe("loop.panel.RoomList", function() {
     var roomListStore, dispatcher, fakeEmail;
 
     beforeEach(function() {
       fakeEmail = "fakeEmail@example.com";
       dispatcher = new loop.Dispatcher();
@@ -770,30 +822,16 @@ describe("loop.panel", function() {
         var dispatch = sandbox.stub(dispatcher, "dispatch");
         roomListStore.setStoreState({pendingInitialRetrieval: true});
 
         var view = createTestComponent();
 
         var buttonNode = view.getDOMNode().querySelector("button[disabled]");
         expect(buttonNode).to.not.equal(null);
       });
-
-    describe("#openRoom", function() {
-      it("should dispatch an OpenRoom action", function() {
-        var view = createTestComponent();
-        var dispatch = sandbox.stub(dispatcher, "dispatch");
-
-        view.openRoom({roomToken: "42cba"});
-
-        sinon.assert.calledOnce(dispatch);
-        sinon.assert.calledWithExactly(dispatch, new sharedActions.OpenRoom({
-          roomToken: "42cba"
-        }));
-      });
-    });
   });
 
   describe('loop.panel.ToSView', function() {
 
     it("should render when the value of loop.seenToS is not set", function() {
       var view = TestUtils.renderIntoDocument(loop.panel.ToSView());
 
       TestUtils.findRenderedDOMComponentWithClass(view, "terms-service");
--- a/browser/components/loop/test/shared/roomListStore_test.js
+++ b/browser/components/loop/test/shared/roomListStore_test.js
@@ -130,19 +130,19 @@ describe("loop.store.RoomListStore", fun
 
           expect(store.getStoreState().rooms).to.have.length.of(3);
           expect(store.getStoreState().rooms.some(function(room) {
             return room.roomName === "Changed First Room Name";
           })).eql(true);
         });
       });
 
-      describe("remove", function() {
-        it("should remove a room from the list", function() {
-          fakeMozLoop.rooms.trigger("remove", "remove", {
+      describe("delete", function() {
+        it("should delete a room from the list", function() {
+          fakeMozLoop.rooms.trigger("delete", "delete", {
             roomToken: "_nxD4V4FflQ"
           });
 
           expect(store.getStoreState().rooms).to.have.length.of(2);
           expect(store.getStoreState().rooms.some(function(room) {
             return room.roomToken === "_nxD4V4FflQ";
           })).eql(false);
         });
--- a/browser/components/loop/test/xpcshell/test_looprooms.js
+++ b/browser/components/loop/test/xpcshell/test_looprooms.js
@@ -257,16 +257,25 @@ add_task(function* test_errorStates() {
 
 // Test if creating a new room works as expected.
 add_task(function* test_createRoom() {
   gExpectedAdds.push(kCreateRoomProps);
   let room = yield LoopRooms.promise("create", kCreateRoomProps);
   compareRooms(room, kCreateRoomProps);
 });
 
+// Test if deleting a room works as expected.
+add_task(function* test_deleteRoom() {
+  let roomToken = "QzBbvGmIZWU";
+  let deletedRoom = yield LoopRooms.promise("delete", roomToken);
+  Assert.equal(deletedRoom.roomToken, roomToken);
+  let rooms = yield LoopRooms.promise("getAll");
+  Assert.ok(!rooms.some((room) => room.roomToken == roomToken));
+});
+
 // Test if opening a new room window works correctly.
 add_task(function* test_openRoom() {
   let openedUrl;
   Chat.open = function(contentWindow, origin, title, url) {
     openedUrl = url;
   };
 
   LoopRooms.open("fakeToken");
--- a/browser/components/loop/ui/ui-showcase.css
+++ b/browser/components/loop/ui/ui-showcase.css
@@ -157,8 +157,29 @@
   bottom: auto;
 }
 
 .standalone .ended-conversation .remote_wrapper,
 .standalone .video-layout-wrapper {
   /* Removes the fake video image for ended conversations */
   background: none;
 }
+
+/* SVG icons showcase */
+
+.svg-icon-entry {
+  width: 180px;
+  float: left;
+}
+
+.svg-icon-entry > p {
+  float: left;
+  margin-right: .5rem;
+}
+
+.svg-icon {
+  display: inline-block;
+  width:  16px;
+  height: 16px;
+  background-repeat: no-repeat;
+  background-size: 16px 16px;
+  background-position: center;
+}
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -96,16 +96,51 @@
   var errNotifications = new loop.shared.models.NotificationCollection();
   errNotifications.add({
     level: "error",
     message: "Could Not Authenticate",
     details: "Did you change your password?",
     detailsButtonLabel: "Retry",
   });
 
+  var SVGIcon = React.createClass({displayName: 'SVGIcon',
+    render: function() {
+      return (
+        React.DOM.span({className: "svg-icon", style: {
+          "background-image": "url(/content/shared/img/icons-16x16.svg#" + this.props.shapeId + ")"
+        }})
+      );
+    }
+  });
+
+  var SVGIcons = React.createClass({displayName: 'SVGIcons',
+    shapes: [
+      "audio", "audio-hover", "audio-active", "block",
+      "block-red", "block-hover", "block-active", "contacts", "contacts-hover",
+      "contacts-active", "copy", "checkmark", "google", "google-hover",
+      "google-active", "history", "history-hover", "history-active",
+      "precall", "precall-hover", "precall-active", "settings", "settings-hover",
+      "settings-active", "tag", "tag-hover", "tag-active", "trash", "unblock",
+      "unblock-hover", "unblock-active", "video", "video-hover", "video-active"
+    ],
+
+    render: function() {
+      return (
+        React.DOM.div({className: "svg-icon-list"}, 
+          this.shapes.map(function(shapeId, i) {
+            return React.DOM.div({className: "svg-icon-entry"}, 
+              React.DOM.p(null, SVGIcon({key: i, shapeId: shapeId})), 
+              React.DOM.p(null, shapeId)
+            );
+          }, this)
+        )
+      );
+    }
+  });
+
   var Example = React.createClass({displayName: 'Example',
     makeId: function(prefix) {
       return (prefix || "") + this.props.summary.toLowerCase().replace(/\s/g, "-");
     },
 
     render: function() {
       var cx = React.addons.classSet;
       return (
@@ -485,16 +520,22 @@
           ), 
 
           Section({name: "UnsupportedDeviceView"}, 
             Example({summary: "Standalone Unsupported Device"}, 
               React.DOM.div({className: "standalone"}, 
                 UnsupportedDeviceView(null)
               )
             )
+          ), 
+
+          Section({name: "SVG icons preview"}, 
+            Example({summary: "16x16"}, 
+              SVGIcons(null)
+            )
           )
 
         )
       );
     }
   });
 
   /**
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -96,16 +96,51 @@
   var errNotifications = new loop.shared.models.NotificationCollection();
   errNotifications.add({
     level: "error",
     message: "Could Not Authenticate",
     details: "Did you change your password?",
     detailsButtonLabel: "Retry",
   });
 
+  var SVGIcon = React.createClass({
+    render: function() {
+      return (
+        <span className="svg-icon" style={{
+          "background-image": "url(/content/shared/img/icons-16x16.svg#" + this.props.shapeId + ")"
+        }} />
+      );
+    }
+  });
+
+  var SVGIcons = React.createClass({
+    shapes: [
+      "audio", "audio-hover", "audio-active", "block",
+      "block-red", "block-hover", "block-active", "contacts", "contacts-hover",
+      "contacts-active", "copy", "checkmark", "google", "google-hover",
+      "google-active", "history", "history-hover", "history-active",
+      "precall", "precall-hover", "precall-active", "settings", "settings-hover",
+      "settings-active", "tag", "tag-hover", "tag-active", "trash", "unblock",
+      "unblock-hover", "unblock-active", "video", "video-hover", "video-active"
+    ],
+
+    render: function() {
+      return (
+        <div className="svg-icon-list">{
+          this.shapes.map(function(shapeId, i) {
+            return <div className="svg-icon-entry">
+              <p><SVGIcon key={i} shapeId={shapeId} /></p>
+              <p>{shapeId}</p>
+            </div>;
+          }, this)
+        }</div>
+      );
+    }
+  });
+
   var Example = React.createClass({
     makeId: function(prefix) {
       return (prefix || "") + this.props.summary.toLowerCase().replace(/\s/g, "-");
     },
 
     render: function() {
       var cx = React.addons.classSet;
       return (
@@ -487,16 +522,22 @@
           <Section name="UnsupportedDeviceView">
             <Example summary="Standalone Unsupported Device">
               <div className="standalone">
                 <UnsupportedDeviceView />
               </div>
             </Example>
           </Section>
 
+          <Section name="SVG icons preview">
+            <Example summary="16x16">
+              <SVGIcons />
+            </Example>
+          </Section>
+
         </ShowCase>
       );
     }
   });
 
   /**
    * Render components that have different styles across
    * CSS media rules in their own iframe to mimic the viewport
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -851,21 +851,17 @@ bin/libfreebl_32int64_3.so
 #endif
 #endif
 
 #ifdef MOZ_WEBAPP_RUNTIME
 [WebappRuntime]
 #ifdef XP_WIN
 @BINPATH@/webapp-uninstaller@BIN_SUFFIX@
 #endif
-#ifdef XP_MACOSX
-@APPNAME@/Contents/MacOS/webapprt-stub@BIN_SUFFIX@
-#else
 @BINPATH@/webapprt-stub@BIN_SUFFIX@
-#endif
 @BINPATH@/webapprt/webapprt.ini
 @BINPATH@/webapprt/chrome.manifest
 @BINPATH@/webapprt/chrome/webapprt@JAREXT@
 @BINPATH@/webapprt/chrome/webapprt.manifest
 @BINPATH@/webapprt/chrome/@AB_CD@@JAREXT@
 @BINPATH@/webapprt/chrome/@AB_CD@.manifest
 @BINPATH@/webapprt/components/CommandLineHandler.js
 @BINPATH@/webapprt/components/ContentPermission.js
--- a/build/win32/mozconfig.vs2013-win64
+++ b/build/win32/mozconfig.vs2013-win64
@@ -1,26 +1,26 @@
 _VSPATH="/c/tools/vs2013"
 export WIN32_REDIST_DIR=${_VSPATH}/VC/redist/x86/Microsoft.VC120.CRT
 
 ## moz tools location for 64-bit builders ##
 export MOZ_TOOLS=C:/mozilla-build/moztools
 
-## includes: win8 sdk includes, winrt headers for metro, msvc std library, directx sdk for d3d9 ##
-export INCLUDE=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/shared:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/um:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt/wrl:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt/wrl/wrappers:${_VSPATH}/vc/include:${_VSPATH}/vc/atlmfc/include:/c/tools/sdks/dx10/include
+## includes: win8.1 sdk includes, winrt headers for metro, msvc std library, directx sdk for d3d9 ##
+export INCLUDE=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/shared:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/um:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/winrt:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/winrt/wrl:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/winrt/wrl/wrappers:${_VSPATH}/vc/include:${_VSPATH}/vc/atlmfc/include:/c/tools/sdks/dx10/include
 
-## libs: win8 sdk x86 (32-bit) libs, msvc (32-bit) std library, msvc atl libs, directx sdk (32-bit) for d3d9  ##
-export LIBPATH=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/Lib/win8/um/x86:${_VSPATH}/vc/lib:${_VSPATH}/vc/atlmfc/lib:/c/tools/sdks/dx10/lib
-export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/Lib/win8/um/x86:${_VSPATH}/vc/lib:${_VSPATH}/vc/atlmfc/lib:/c/tools/sdks/dx10/lib
+## libs: win8.1 sdk x86 (32-bit) libs, msvc (32-bit) std library, msvc atl libs, directx sdk (32-bit) for d3d9  ##
+export LIBPATH=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/Lib/winv6.3/um/x86:${_VSPATH}/vc/lib:${_VSPATH}/vc/atlmfc/lib:/c/tools/sdks/dx10/lib
+export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/Lib/winv6.3/um/x86:${_VSPATH}/vc/lib:${_VSPATH}/vc/atlmfc/lib:/c/tools/sdks/dx10/lib
 
-## paths: win8 sdk x86 (32-bit) tools, msvc (64-bit compiling 32-bit) build toolchain, moz tools  ##
-export PATH="/c/Program Files (x86)/Windows Kits/8.0/bin/x86:${_VSPATH}/Common7/IDE:${_VSPATH}/VC/BIN/amd64_x86:${_VSPATH}/VC/BIN/amd64:${_VSPATH}/Common7/Tools:${_VSPATH}/VC/VCPackages:/c/mozilla-build/moztools:${PATH}"
+## paths: win8.1 sdk x86 (32-bit) tools, msvc (64-bit compiling 32-bit) build toolchain, moz tools  ##
+export PATH="/c/Program Files (x86)/Windows Kits/8.1/bin/x86:${_VSPATH}/Common7/IDE:${_VSPATH}/VC/BIN/amd64_x86:${_VSPATH}/VC/BIN/amd64:${_VSPATH}/Common7/Tools:${_VSPATH}/VC/VCPackages:/c/mozilla-build/moztools:${PATH}"
 
 ## WindowsSDKDir ##
-export WINDOWSSDKDIR="/c/Program Files (x86)/Windows Kits/8.0/"
+export WINDOWSSDKDIR="/c/Program Files (x86)/Windows Kits/8.1/"
 
 . $topsrcdir/build/mozconfig.vs-common
 
 mk_export_correct_style LIB
 mk_export_correct_style LIBPATH
 mk_export_correct_style PATH
 mk_export_correct_style INCLUDE
 mk_export_correct_style WIN32_REDIST_DIR
--- a/build/win64/mozconfig.vs2013
+++ b/build/win64/mozconfig.vs2013
@@ -1,23 +1,23 @@
 _VSPATH="/c/tools/vs2013"
 export WIN32_REDIST_DIR=${_VSPATH}/VC/redist/x64/Microsoft.VC120.CRT
 
-## includes: win8 sdk includes, winrt headers for metro, msvc 10 std library, directx sdk for d3d9 ##
-export INCLUDE=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/shared:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/um:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt/wrl:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt/wrl/wrappers:${_VSPATH}/vc/include:${_VSPATH}/vc/atlmfc/include:/c/tools/sdks/dx10/include
+## includes: win8.1 sdk includes, winrt headers for metro, msvc std library, directx sdk for d3d9 ##
+export INCLUDE=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/shared:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/um:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/winrt:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/winrt/wrl:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/include/winrt/wrl/wrappers:${_VSPATH}/vc/include:${_VSPATH}/vc/atlmfc/include:/c/tools/sdks/dx10/include
 
-## libs: win8 sdk x64 (64-bit) libs, msvc 10 (64-bit) std library, msvc 10 atl libs, directx sdk (64-bit) for d3d9  ##
-export LIBPATH=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/Lib/win8/um/x64:${_VSPATH}/vc/lib/amd64:${_VSPATH}/vc/atlmfc/lib/amd64:/c/tools/sdks/dx10/lib/x64
-export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/Lib/win8/um/x64:${_VSPATH}/vc/lib/amd64:${_VSPATH}/vc/atlmfc/lib/amd64:/c/tools/sdks/dx10/lib/x64
+## libs: win8.1 sdk x64 (64-bit) libs, msvc (64-bit) std library, msvc atl libs, directx sdk (64-bit) for d3d9  ##
+export LIBPATH=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/Lib/winv6.3/um/x64:${_VSPATH}/vc/lib/amd64:${_VSPATH}/vc/atlmfc/lib/amd64:/c/tools/sdks/dx10/lib/x64
+export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.1/Lib/winv6.3/um/x64:${_VSPATH}/vc/lib/amd64:${_VSPATH}/vc/atlmfc/lib/amd64:/c/tools/sdks/dx10/lib/x64
 
-## paths: win8 sdk x64 (64-bit) tools, msvc 10 (64-bit) build toolchain, moz tools  ##
-export PATH="/c/Program Files (x86)/Windows Kits/8.0/bin/x64:${_VSPATH}/Common7/IDE:${_VSPATH}/VC/BIN/amd64:${_VSPATH}/VC/BIN/x86_amd64:${_VSPATH}/VC/BIN:${_VSPATH}/Common7/Tools:${_VSPATH}/VC/VCPackages:${PATH}"
+## paths: win8.1 sdk x64 (64-bit) tools, msvc (64-bit) build toolchain, moz tools  ##
+export PATH="/c/Program Files (x86)/Windows Kits/8.1/bin/x64:${_VSPATH}/Common7/IDE:${_VSPATH}/VC/BIN/amd64:${_VSPATH}/VC/BIN/x86_amd64:${_VSPATH}/VC/BIN:${_VSPATH}/Common7/Tools:${_VSPATH}/VC/VCPackages:${PATH}"
 
 ## WindowsSDKDir ##
-export WINDOWSSDKDIR="/c/Program Files (x86)/Windows Kits/8.0/"
+export WINDOWSSDKDIR="/c/Program Files (x86)/Windows Kits/8.1/"
 
 . $topsrcdir/build/mozconfig.vs-common
 
 mk_export_correct_style LIB
 mk_export_correct_style LIBPATH
 mk_export_correct_style PATH
 mk_export_correct_style INCLUDE
 mk_export_correct_style WIN32_REDIST_DIR
--- a/docshell/test/navigation/mochitest.ini
+++ b/docshell/test/navigation/mochitest.ini
@@ -39,14 +39,14 @@ skip-if = (buildapp == 'b2g' && (toolkit
 [test_grandchild.html]
 [test_not-opener.html]
 skip-if = buildapp == 'b2g' || (toolkit == 'android' && processor == 'x86') #x86 only
 [test_opener.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_popup-navigates-children.html]
 skip-if = buildapp == 'b2g' # b2g(Needs multiple window.open support, also uses docshelltreenode) b2g-debug(Needs multiple window.open support, also uses docshelltreenode) b2g-desktop(Needs multiple window.open support, also uses docshelltreenode)
 [test_reserved.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || android_version == '10' #too slow on Android 2.3 aws only; bug 1030403
 [test_sessionhistory.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #RANDOM # b2g-debug(Perma-orange on debug emulator builds) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_sibling-matching-parent.html]
 [test_sibling-off-domain.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -6,16 +6,17 @@ support-files =
 [webgl-mochitest/test-backbuffer-channels.html]
 [webgl-mochitest/test-hidden-alpha.html]
 [webgl-mochitest/test_depth_readpixels.html]
 [webgl-mochitest/test_draw.html]
 [webgl-mochitest/test_fb_param.html]
 [webgl-mochitest/test_fb_param_crash.html]
 [webgl-mochitest/test_highp_fs.html]
 [webgl-mochitest/test_no_arr_points.html]
+skip-if = android_version == '10' #Android 2.3 aws only; bug 1030942
 [webgl-mochitest/test_noprog_draw.html]
 [webgl-mochitest/test_privileged_exts.html]
 [webgl-mochitest/test_texsubimage_float.html]
 [webgl-mochitest/test_webgl_available.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl_conformance.html]
 skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl_request_context.html]
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -390,17 +390,17 @@ support-files =
   bug649134/file_bug649134-1.sjs
   bug649134/file_bug649134-2.sjs
   bug649134/index.html
 [test_bug651956.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug658746.html]
 [test_bug659596.html]
 [test_bug659743.xml]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || android_version == '10' #Bug 931116, b2g desktop specific, initial triage #Android 2.3 aws only; bug 1031103
 [test_bug660663.html]
 [test_bug660959-1.html]
 [test_bug660959-2.html]
 [test_bug660959-3.html]
 [test_bug666200.html]
 [test_bug666666.html]
 [test_bug669012.html]
 [test_bug674558.html]
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1903,16 +1903,27 @@ ContentChild::RecvGeolocationUpdate(cons
         return true;
     }
     nsCOMPtr<nsIDOMGeoPosition> position = somewhere;
     gs->Update(position);
     return true;
 }
 
 bool
+ContentChild::RecvGeolocationError(const uint16_t& errorCode)
+{
+    nsCOMPtr<nsIGeolocationUpdate> gs = do_GetService("@mozilla.org/geolocation/service;1");
+    if (!gs) {
+        return true;
+    }
+    gs->NotifyError(errorCode);
+    return true;
+}
+
+bool
 ContentChild::RecvUpdateDictionaryList(const InfallibleTArray<nsString>& aDictionaries)
 {
     mAvailableDictionaries = aDictionaries;
     mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
     return true;
 }
 
 bool
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -300,16 +300,18 @@ public:
 
     virtual bool RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
                                   const InfallibleTArray<CpowEntry>& aCpows,
                                   const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
     virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere) MOZ_OVERRIDE;
 
+    virtual bool RecvGeolocationError(const uint16_t& errorCode) MOZ_OVERRIDE;
+
     virtual bool RecvUpdateDictionaryList(const InfallibleTArray<nsString>& aDictionaries) MOZ_OVERRIDE;
 
     virtual bool RecvAddPermission(const IPC::Permission& permission) MOZ_OVERRIDE;
 
     virtual bool RecvScreenSizeChanged(const gfxIntSize &size) MOZ_OVERRIDE;
 
     virtual bool RecvFlushMemory(const nsString& reason) MOZ_OVERRIDE;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -88,16 +88,17 @@
 #include "nsFrameMessageManager.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIAppsService.h"
 #include "nsIClipboard.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIDocument.h"
 #include "nsIDOMGeoGeolocation.h"
+#include "nsIDOMGeoPositionError.h"
 #include "mozilla/dom/WakeLock.h"
 #include "nsIDOMWindow.h"
 #include "nsIExternalProtocolService.h"
 #include "nsIGfxInfo.h"
 #include "nsIIdleService.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIMemoryInfoDumper.h"
 #include "nsIMemoryReporter.h"
@@ -2585,16 +2586,17 @@ NS_IMPL_CYCLE_COLLECTION_0(ContentParent
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent)
   NS_INTERFACE_MAP_ENTRY(nsIContentParent)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionErrorCallback)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMETHODIMP
 ContentParent::Observe(nsISupports* aSubject,
                        const char* aTopic,
                        const char16_t* aData)
 {
@@ -3684,29 +3686,29 @@ ContentParent::RecvFilePathUpdateNotify(
         return false;
     }
     obs->NotifyObservers(dsf, "file-watcher-update",
                          NS_ConvertASCIItoUTF16(aReason).get());
     return true;
 }
 
 static int32_t
-AddGeolocationListener(nsIDOMGeoPositionCallback* watcher, bool highAccuracy)
+AddGeolocationListener(nsIDOMGeoPositionCallback* watcher, nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy)
 {
     nsCOMPtr<nsIDOMGeoGeolocation> geo = do_GetService("@mozilla.org/geolocation;1");
     if (!geo) {
         return -1;
     }
 
     PositionOptions* options = new PositionOptions();
     options->mTimeout = 0;
     options->mMaximumAge = 0;
     options->mEnableHighAccuracy = highAccuracy;
     int32_t retval = 1;
-    geo->WatchPosition(watcher, nullptr, options, &retval);
+    geo->WatchPosition(watcher, errorCallBack, options, &retval);
     return retval;
 }
 
 bool
 ContentParent::RecvAddGeolocationListener(const IPC::Principal& aPrincipal,
                                           const bool& aHighAccuracy)
 {
 #ifdef MOZ_CHILD_PERMISSIONS
@@ -3717,17 +3719,17 @@ ContentParent::RecvAddGeolocationListene
             return true;
         }
     }
 #endif /* MOZ_CHILD_PERMISSIONS */
 
     // To ensure no geolocation updates are skipped, we always force the
     // creation of a new listener.
     RecvRemoveGeolocationListener();
-    mGeolocationWatchID = AddGeolocationListener(this, aHighAccuracy);
+    mGeolocationWatchID = AddGeolocationListener(this, this, aHighAccuracy);
     return true;
 }
 
 bool
 ContentParent::RecvRemoveGeolocationListener()
 {
     if (mGeolocationWatchID != -1) {
         nsCOMPtr<nsIDOMGeoGeolocation> geo = do_GetService("@mozilla.org/geolocation;1");
@@ -3742,28 +3744,39 @@ ContentParent::RecvRemoveGeolocationList
 
 bool
 ContentParent::RecvSetGeolocationHigherAccuracy(const bool& aEnable)
 {
     // This should never be called without a listener already present,
     // so this check allows us to forgo securing privileges.
     if (mGeolocationWatchID != -1) {
         RecvRemoveGeolocationListener();
-        mGeolocationWatchID = AddGeolocationListener(this, aEnable);
+        mGeolocationWatchID = AddGeolocationListener(this, this, aEnable);
     }
     return true;
 }
 
 NS_IMETHODIMP
 ContentParent::HandleEvent(nsIDOMGeoPosition* postion)
 {
     unused << SendGeolocationUpdate(GeoPosition(postion));
     return NS_OK;
 }
 
+NS_IMETHODIMP
+ContentParent::HandleEvent(nsIDOMGeoPositionError* postionError)
+{
+    int16_t errorCode;
+    nsresult rv;
+    rv = postionError->GetCode(&errorCode);
+    NS_ENSURE_SUCCESS(rv,rv);
+    unused << SendGeolocationError(errorCode);
+    return NS_OK;
+}
+
 nsConsoleService *
 ContentParent::GetConsoleService()
 {
     if (mConsoleService) {
         return mConsoleService.get();
     }
 
     // Get the ConsoleService by CID rather than ContractID, so that we
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -17,16 +17,17 @@
 #include "mozilla/StaticPtr.h"
 
 #include "nsDataHashtable.h"
 #include "nsFrameMessageManager.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsIThreadInternal.h"
 #include "nsIDOMGeoPositionCallback.h"
+#include "nsIDOMGeoPositionErrorCallback.h"
 #include "PermissionMessageUtils.h"
 
 #define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
 
 class mozIApplication;
 class nsConsoleService;
 class nsICycleCollectorLogSink;
 class nsIDOMBlob;
@@ -63,16 +64,17 @@ class ClonedMessageData;
 class MemoryReport;
 class TabContext;
 class ContentBridgeParent;
 
 class ContentParent MOZ_FINAL : public PContentParent
                               , public nsIContentParent
                               , public nsIObserver
                               , public nsIDOMGeoPositionCallback
+                              , public nsIDOMGeoPositionErrorCallback
                               , public mozilla::LinkedListElement<ContentParent>
 {
     typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
     typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
     typedef mozilla::ipc::PFileDescriptorSetParent PFileDescriptorSetParent;
     typedef mozilla::ipc::TestShellParent TestShellParent;
     typedef mozilla::ipc::URIParams URIParams;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
@@ -155,16 +157,17 @@ public:
                                  nsTArray<PluginTag>* aPlugins,
                                  uint32_t* aNewPluginEpoch) MOZ_OVERRIDE;
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSIDOMGEOPOSITIONCALLBACK
+    NS_DECL_NSIDOMGEOPOSITIONERRORCALLBACK
 
     /**
      * MessageManagerCallback methods that we override.
      */
     virtual bool DoSendAsyncMessage(JSContext* aCx,
                                     const nsAString& aMessage,
                                     const mozilla::dom::StructuredCloneData& aData,
                                     JS::Handle<JSObject *> aCpows,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -444,16 +444,18 @@ child:
     async SystemMemoryAvailable(uint64_t getterId, uint32_t memoryAvailable);
 
     PreferenceUpdate(PrefSetting pref);
 
     NotifyAlertsObserver(nsCString topic, nsString data);
 
     GeolocationUpdate(GeoPosition somewhere);
 
+    GeolocationError(uint16_t errorCode);
+
     UpdateDictionaryList(nsString[] dictionaries);
 
     // nsIPermissionManager messages
     AddPermission(Permission permission);
 
     ScreenSizeChanged(gfxIntSize size);
 
     FlushMemory(nsString reason);
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = (os == 'win' && contentSandbox != 'off') # contentSandbox(Bug 1042735)
+skip-if = (os == 'win' && contentSandbox != 'off') || android_version == '10' # contentSandbox(Bug 1042735) #Android 2.3 only; bug 981881
 support-files =
   head.js
   constraints.js
   mediaStreamPlayback.js
   nonTrickleIce.js
   pc.js
   templates.js
   NetworkPreparationChromeScript.js
--- a/dom/permission/tests/mochitest-bt.ini
+++ b/dom/permission/tests/mochitest-bt.ini
@@ -1,1 +1,2 @@
 [test_bluetooth.html]
+skip-if = (toolkit == 'gonk' && debug) # bug 1093079
new file mode 100644
--- /dev/null
+++ b/dom/tests/unit/test_geolocation_position_unavailable.js
@@ -0,0 +1,36 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+
+function successCallback() {
+  do_check_true(false);
+  do_test_finished();
+}
+
+function errorCallback(err) {
+  do_check_eq(Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE, err.code);
+  do_test_finished();
+}
+
+function run_test()
+{
+  do_test_pending();
+
+  if (Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
+        .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
+    // XPCShell does not get a profile by default. The geolocation service
+    // depends on the settings service which uses IndexedDB and IndexedDB
+    // needs a place where it can store databases.
+    do_get_profile();
+
+    var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+    prefs.setBoolPref("geo.wifi.scan", false);
+    prefs.setCharPref("geo.wifi.uri", "UrlNotUsedHere:");
+    prefs.setBoolPref("dom.testing.ignore_ipc_principal", true);
+  }
+
+  geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsISupports);
+  geolocation.getCurrentPosition(successCallback, errorCallback);
+}
new file mode 100644
--- /dev/null
+++ b/dom/tests/unit/test_geolocation_position_unavailable_wrap.js
@@ -0,0 +1,13 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+
+function run_test() {
+  var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+  prefs.setBoolPref("geo.wifi.scan", false);
+
+  prefs.setCharPref("geo.wifi.uri", "UrlNotUsedHere");
+  prefs.setBoolPref("dom.testing.ignore_ipc_principal", true);
+  run_test_in_child("./test_geolocation_position_unavailable.js");
+}
--- a/dom/tests/unit/xpcshell.ini
+++ b/dom/tests/unit/xpcshell.ini
@@ -13,9 +13,13 @@ skip-if = os == "android"
 skip-if = os == "android"
 [test_geolocation_timeout_wrap.js]
 skip-if = os == "mac" || os == "android"
 [test_geolocation_reset_accuracy.js]
 # Bug 919946: test hangs consistently on Android
 skip-if = os == "android"
 [test_geolocation_reset_accuracy_wrap.js]
 skip-if = os == "mac" || os == "android"
+[test_geolocation_position_unavailable.js]
+skip-if = os == "android"
+[test_geolocation_position_unavailable_wrap.js]
+skip-if = os == "mac" || os == "android"
 [test_PromiseDebugging.js]
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -742,17 +742,17 @@ MessageChannel::SendAndWait(Message* aMs
             if (mRecvd->is_reply_error()) {
                 mRecvd = nullptr;
                 return false;
             }
 
             MOZ_ASSERT(mRecvd->type() == replyType, "wrong reply type");
             MOZ_ASSERT(mRecvd->seqno() == replySeqno);
 
-            *aReply = *mRecvd;
+            *aReply = Move(*mRecvd);
             mRecvd = nullptr;
             return true;
         }
 
         bool maybeTimedOut = !WaitForSyncNotify();
 
         if (!Connected()) {
             ReportConnectionError("MessageChannel::SendAndWait");
@@ -833,20 +833,20 @@ MessageChannel::Call(Message* aMsg, Mess
         }
 
         Message recvd;
         MessageMap::iterator it;
 
         if ((it = mOutOfTurnReplies.find(mInterruptStack.top().seqno()))
             != mOutOfTurnReplies.end())
         {
-            recvd = it->second;
+            recvd = Move(it->second);
             mOutOfTurnReplies.erase(it);
         } else if (!mPending.empty()) {
-            recvd = mPending.front();
+            recvd = Move(mPending.front());
             mPending.pop_front();
         } else {
             // because of subtleties with nested event loops, it's possible
             // that we got here and nothing happened.  or, we might have a
             // deferred in-call that needs to be processed.  either way, we
             // won't break the inner while loop again until something new
             // happens.
             continue;
@@ -877,41 +877,42 @@ MessageChannel::Call(Message* aMsg, Mess
             {
                 const Message &outcall = mInterruptStack.top();
 
                 // Note, In the parent, sequence numbers increase from 0, and
                 // in the child, they decrease from 0.
                 if ((mSide == ChildSide && recvd.seqno() > outcall.seqno()) ||
                     (mSide != ChildSide && recvd.seqno() < outcall.seqno()))
                 {
-                    mOutOfTurnReplies[recvd.seqno()] = recvd;
+                    mOutOfTurnReplies[recvd.seqno()] = Move(recvd);
                     continue;
                 }
 
                 IPC_ASSERT(recvd.is_reply_error() ||
                            (recvd.type() == (outcall.type() + 1) &&
                             recvd.seqno() == outcall.seqno()),
                            "somebody's misbehavin'", true);
             }
 
             // We received a reply to our most recent outstanding call. Pop
             // this frame and return the reply.
             mInterruptStack.pop();
 
-            if (!recvd.is_reply_error()) {
-                *aReply = recvd;
+            bool is_reply_error = recvd.is_reply_error();
+            if (!is_reply_error) {
+                *aReply = Move(recvd);
             }
 
             // If we have no more pending out calls waiting on replies, then
             // the reply queue should be empty.
             IPC_ASSERT(!mInterruptStack.empty() || mOutOfTurnReplies.empty(),
                        "still have pending replies with no pending out-calls",
                        true);
 
-            return !recvd.is_reply_error();
+            return !is_reply_error;
         }
 
         // Dispatch an Interrupt in-call. Snapshot the current stack depth while we
         // own the monitor.
         size_t stackDepth = InterruptStackDepth();
         {
             MonitorAutoUnlock unlock(*mMonitor);
 
@@ -1012,17 +1013,17 @@ MessageChannel::OnMaybeDequeueOne()
 
     MonitorAutoLock lock(*mMonitor);
     if (!DequeueOne(&recvd))
         return false;
 
     if (IsOnCxxStack() && recvd.is_interrupt() && recvd.is_reply()) {
         // We probably just received a reply in a nested loop for an
         // Interrupt call sent before entering that loop.
-        mOutOfTurnReplies[recvd.seqno()] = recvd;
+        mOutOfTurnReplies[recvd.seqno()] = Move(recvd);
         return false;
     }
 
     {
         // We should not be in a transaction yet if we're not blocked.
         MOZ_ASSERT(mCurrentTransaction == 0);
         AutoEnterTransaction transaction(this, recvd);
 
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -152,30 +152,29 @@ support-files = BitPattern.woff
 [test_inherit_computation.html]
 skip-if = toolkit == 'android'
 [test_inherit_storage.html]
 [test_initial_computation.html]
 skip-if = toolkit == 'android'
 [test_initial_storage.html]
 [test_keyframes_rules.html]
 [test_media_queries.html]
-skip-if = (toolkit == 'gonk' && debug) #debug-only failure; timed out
+skip-if = (toolkit == 'gonk' && debug) || android_version == '10' #debug-only failure; timed out #Android 2.3 aws only; bug 1030419
 [test_media_queries_dynamic.html]
 [test_media_queries_dynamic_xbl.html]
 [test_media_query_list.html]
 [test_moz_device_pixel_ratio.html]
 [test_namespace_rule.html]
 [test_of_type_selectors.xhtml]
 [test_parse_eof.html]
 [test_parse_ident.html]
 [test_parse_rule.html]
 [test_parse_url.html]
 [test_parser_diagnostics_unprintables.html]
 [test_pixel_lengths.html]
-skip-if = true # bug 891840 - intermittent crashes
 [test_pointer-events.html]
 [test_position_sticky.html]
 support-files = file_position_sticky.html
 [test_priority_preservation.html]
 [test_property_syntax_errors.html]
 [test_pseudoelement_state.html]
 skip-if = (toolkit == 'gonk' && debug) || e10s #debug-only failure
 [test_pseudoelement_parsing.html]
@@ -196,16 +195,17 @@ skip-if = (toolkit == 'gonk' && debug) |
 [test_style_attribute_standards.html]
 [test_style_struct_copy_constructors.html]
 [test_supports_rules.html]
 [test_system_font_serialization.html]
 [test_transitions_and_reframes.html]
 [test_transitions_and_restyles.html]
 [test_transitions_and_zoom.html]
 [test_transitions_cancel_near_end.html]
+skip-if = android_version == '10' #Android 2.3 aws only; bug 1030432
 [test_transitions_computed_values.html]
 [test_transitions_computed_value_combinations.html]
 [test_transitions_events.html]
 [test_transitions.html]
 [test_transitions_per_property.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 775227 # b2g(times out, needs more time + various failures) b2g-debug(times out, needs more time + various failures) b2g-desktop(times out, needs more time + various failures)
 [test_transitions_step_functions.html]
 [test_transitions_dynamic_changes.html]
--- a/security/pkix/lib/pkixcert.cpp
+++ b/security/pkix/lib/pkixcert.cpp
@@ -217,31 +217,46 @@ BackCert::RememberExtension(Reader& extn
   // python DottedOIDToCode.py id-ce-inhibitAnyPolicy 2.5.29.54
   static const uint8_t id_ce_inhibitAnyPolicy[] = {
     0x55, 0x1d, 0x36
   };
   // python DottedOIDToCode.py id-pe-authorityInfoAccess 1.3.6.1.5.5.7.1.1
   static const uint8_t id_pe_authorityInfoAccess[] = {
     0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
   };
+  // python DottedOIDToCode.py id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5
+  static const uint8_t id_pkix_ocsp_nocheck[] = {
+    0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05
+  };
   // python DottedOIDToCode.py Netscape-certificate-type 2.16.840.1.113730.1.1
   static const uint8_t Netscape_certificate_type[] = {
     0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01
   };
 
   Input* out = nullptr;
 
   // We already enforce the maximum possible constraints for policies so we
   // can safely ignore even critical policy constraint extensions.
   //
   // XXX: Doing it this way won't allow us to detect duplicate
   // policyConstraints extensions, but that's OK because (and only because) we
   // ignore the extension.
   Input dummyPolicyConstraints;
 
+  // We don't need to save the contents of this extension if it is present. We
+  // just need to handle its presence (it is essentially ignored right now).
+  Input dummyOCSPNocheck;
+
+  // For compatibility reasons, for some extensions we have to allow empty
+  // extension values. This would normally interfere with our duplicate
+  // extension checking code. However, as long as the extensions we allow to
+  // have empty values are also the ones we implicitly allow duplicates of,
+  // this will work fine.
+  bool emptyValueAllowed = false;
+
   // RFC says "Conforming CAs MUST mark this extension as non-critical" for
   // both authorityKeyIdentifier and subjectKeyIdentifier, and we do not use
   // them for anything, so we totally ignore them here.
 
   if (extnID.MatchRest(id_ce_keyUsage)) {
     out = &keyUsage;
   } else if (extnID.MatchRest(id_ce_subjectAltName)) {
     out = &subjectAltName;
@@ -254,24 +269,35 @@ BackCert::RememberExtension(Reader& extn
   } else if (extnID.MatchRest(id_ce_policyConstraints)) {
     out = &dummyPolicyConstraints;
   } else if (extnID.MatchRest(id_ce_extKeyUsage)) {
     out = &extKeyUsage;
   } else if (extnID.MatchRest(id_ce_inhibitAnyPolicy)) {
     out = &inhibitAnyPolicy;
   } else if (extnID.MatchRest(id_pe_authorityInfoAccess)) {
     out = &authorityInfoAccess;
+  } else if (extnID.MatchRest(id_pkix_ocsp_nocheck) && critical) {
+    // We need to make sure we don't reject delegated OCSP response signing
+    // certificates that contain the id-pkix-ocsp-nocheck extension marked as
+    // critical when validating OCSP responses. Without this, an application
+    // that implements soft-fail OCSP might ignore a valid Revoked or Unknown
+    // response, and an application that implements hard-fail OCSP might fail
+    // to connect to a server given a valid Good response.
+    out = &dummyOCSPNocheck;
+    // We allow this extension to have an empty value.
+    // See http://comments.gmane.org/gmane.ietf.x509/30947
+    emptyValueAllowed = true;
   } else if (extnID.MatchRest(Netscape_certificate_type) && critical) {
     out = &criticalNetscapeCertificateType;
   }
 
   if (out) {
     // Don't allow an empty value for any extension we understand. This way, we
     // can test out->GetLength() != 0 or out->Init() to check for duplicates.
-    if (extnValue.GetLength() == 0) {
+    if (extnValue.GetLength() == 0 && !emptyValueAllowed) {
       return Result::ERROR_EXTENSION_VALUE_INVALID;
     }
     if (out->Init(extnValue) != Success) {
       // Duplicate extension
       return Result::ERROR_EXTENSION_VALUE_INVALID;
     }
     understood = true;
   }
--- a/security/pkix/test/gtest/pkixcert_extension_tests.cpp
+++ b/security/pkix/test/gtest/pkixcert_extension_tests.cpp
@@ -18,16 +18,17 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "pkix/pkix.h"
+#include "pkixder.h"
 #include "pkixgtest.h"
 #include "pkixtestutil.h"
 
 using namespace mozilla::pkix;
 using namespace mozilla::pkix::test;
 
 // Creates a self-signed certificate with the given extension.
 static ByteString
@@ -102,221 +103,196 @@ private:
   }
 
   virtual Result CheckPublicKey(Input subjectPublicKeyInfo)
   {
     return TestCheckPublicKey(subjectPublicKeyInfo);
   }
 };
 
-class pkixcert_extension : public ::testing::Test
+// python DottedOIDToCode.py --tlv unknownExtensionOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
+static const uint8_t tlv_unknownExtensionOID[] = {
+  0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a, 0x85, 0x1a,
+  0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03
+};
+
+// python DottedOIDToCode.py --tlv id-pe-authorityInformationAccess 1.3.6.1.5.5.7.1.1
+static const uint8_t tlv_id_pe_authorityInformationAccess[] = {
+  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
+};
+
+// python DottedOIDToCode.py --tlv wrongExtensionOID 1.3.6.6.1.5.5.7.1.1
+// (there is an extra "6" that shouldn't be in this OID)
+static const uint8_t tlv_wrongExtensionOID[] = {
+  0x06, 0x09, 0x2b, 0x06, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
+};
+
+// python DottedOIDToCode.py --tlv id-ce-unknown 2.5.29.55
+// (this is a made-up OID for testing "id-ce"-prefixed OIDs that mozilla::pkix
+// doesn't handle)
+static const uint8_t tlv_id_ce_unknown[] = {
+  0x06, 0x03, 0x55, 0x1d, 0x37
+};
+
+// python DottedOIDToCode.py --tlv id-ce-inhibitAnyPolicy 2.5.29.54
+static const uint8_t tlv_id_ce_inhibitAnyPolicy[] = {
+  0x06, 0x03, 0x55, 0x1d, 0x36
+};
+
+// python DottedOIDToCode.py --tlv id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5
+static const uint8_t tlv_id_pkix_ocsp_nocheck[] = {
+  0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05
+};
+
+template <size_t L>
+inline ByteString
+BytesToByteString(const uint8_t (&bytes)[L])
+{
+  return ByteString(bytes, L);
+}
+
+struct ExtensionTestcase
+{
+  ByteString extension;
+  Result expectedResult;
+};
+
+static const ExtensionTestcase EXTENSION_TESTCASES[] =
+{
+  // Tests that a non-critical extension not in the id-ce or id-pe arcs (which
+  // is thus unknown to us) verifies successfully even if empty (extensions we
+  // know about aren't normally allowed to be empty).
+  { TLV(der::SEQUENCE,
+        BytesToByteString(tlv_unknownExtensionOID) +
+        TLV(der::OCTET_STRING, ByteString())),
+    Success
+  },
+
+  // Tests that a critical extension not in the id-ce or id-pe arcs (which is
+  // thus unknown to us) is detected and that verification fails with the
+  // appropriate error.
+  { TLV(der::SEQUENCE,
+        BytesToByteString(tlv_unknownExtensionOID) +
+        Boolean(true) +
+        TLV(der::OCTET_STRING, ByteString())),
+    Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
+  },
+
+  // Tests that a id-pe-authorityInformationAccess critical extension
+  // is detected and that verification succeeds.
+  // XXX: According to RFC 5280 an AIA that consists of an empty sequence is
+  // not legal, but we accept it and that is not what we're testing here.
+  { TLV(der::SEQUENCE,
+        BytesToByteString(tlv_id_pe_authorityInformationAccess) +
+        Boolean(true) +
+        TLV(der::OCTET_STRING, TLV(der::SEQUENCE, ByteString()))),
+    Success
+  },
+
+  // Tests that an incorrect OID for id-pe-authorityInformationAccess
+  // (when marked critical) is detected and that verification fails.
+  // (Until bug 1020993 was fixed, this wrong value was used for
+  // id-pe-authorityInformationAccess.)
+  { TLV(der::SEQUENCE,
+        BytesToByteString(tlv_wrongExtensionOID) +
+        Boolean(true) +
+        TLV(der::OCTET_STRING, ByteString())),
+    Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
+  },
+
+  // We know about some id-ce extensions (OID arc 2.5.29), but not all of them.
+  // Tests that an unknown id-ce extension is detected and that verification
+  // fails.
+  { TLV(der::SEQUENCE,
+        BytesToByteString(tlv_id_ce_unknown) +
+        Boolean(true) +
+        TLV(der::OCTET_STRING, ByteString())),
+    Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
+  },
+
+  // Tests that a certificate with a known critical id-ce extension (in this
+  // case, OID 2.5.29.54, which is id-ce-inhibitAnyPolicy), verifies
+  // successfully.
+  { TLV(der::SEQUENCE,
+        BytesToByteString(tlv_id_ce_inhibitAnyPolicy) +
+        Boolean(true) +
+        TLV(der::OCTET_STRING, Integer(0))),
+    Success
+  },
+
+  // Tests that a certificate with the id-pkix-ocsp-nocheck extension (marked
+  // critical) verifies successfully.
+  // RFC 6960:
+  //   ext-ocsp-nocheck EXTENSION ::= { SYNTAX NULL IDENTIFIED
+  //                                    BY id-pkix-ocsp-nocheck }
+  { TLV(der::SEQUENCE,
+        BytesToByteString(tlv_id_pkix_ocsp_nocheck) +
+        Boolean(true) +
+        TLV(der::OCTET_STRING, TLV(der::NULLTag, ByteString()))),
+    Success
+  },
+
+  // Tests that a certificate with another representation of the
+  // id-pkix-ocsp-nocheck extension (marked critical) verifies successfully.
+  // According to http://comments.gmane.org/gmane.ietf.x509/30947,
+  // some code creates certificates where value of the extension is
+  // an empty OCTET STRING.
+  { TLV(der::SEQUENCE,
+        BytesToByteString(tlv_id_pkix_ocsp_nocheck) +
+        Boolean(true) +
+        TLV(der::OCTET_STRING, ByteString())),
+    Success
+  },
+};
+
+class pkixcert_extension
+  : public ::testing::Test
+  , public ::testing::WithParamInterface<ExtensionTestcase>
 {
 protected:
   static TrustEverythingTrustDomain trustDomain;
 };
 
 /*static*/ TrustEverythingTrustDomain pkixcert_extension::trustDomain;
 
-// Tests that a critical extension not in the id-ce or id-pe arcs (which is
-// thus unknown to us) is detected and that verification fails with the
-// appropriate error.
-TEST_F(pkixcert_extension, UnknownCriticalExtension)
+TEST_P(pkixcert_extension, ExtensionHandledProperly)
 {
-  static const uint8_t unknownCriticalExtensionBytes[] = {
-    0x30, 0x19, // SEQUENCE (length = 25)
-      0x06, 0x12, // OID (length = 18)
-        // 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
-        0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a,
-        0x85, 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03,
-      0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE
-      0x04, 0x00 // OCTET STRING (length = 0)
-  };
-  static const ByteString
-    unknownCriticalExtension(unknownCriticalExtensionBytes,
-                             sizeof(unknownCriticalExtensionBytes));
-  const char* certCN = "Cert With Unknown Critical Extension";
-  ByteString cert(CreateCertWithOneExtension(certCN, unknownCriticalExtension));
+  const ExtensionTestcase& testcase(GetParam());
+  const char* cn = "Cert Extension Test";
+  ByteString cert(CreateCertWithOneExtension(cn, testcase.extension));
   ASSERT_FALSE(ENCODING_FAILED(cert));
   Input certInput;
   ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
-  ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
-            BuildCertChain(trustDomain, certInput, Now(),
-                           EndEntityOrCA::MustBeEndEntity,
-                           KeyUsage::noParticularKeyUsageRequired,
-                           KeyPurposeId::anyExtendedKeyUsage,
-                           CertPolicyId::anyPolicy,
-                           nullptr/*stapledOCSPResponse*/));
-}
-
-// Tests that a non-critical extension not in the id-ce or id-pe arcs (which is
-// thus unknown to us) verifies successfully.
-TEST_F(pkixcert_extension, UnknownNonCriticalExtension)
-{
-  static const uint8_t unknownNonCriticalExtensionBytes[] = {
-    0x30, 0x16, // SEQUENCE (length = 22)
-      0x06, 0x12, // OID (length = 18)
-        // 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
-        0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a,
-        0x85, 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03,
-      0x04, 0x00 // OCTET STRING (length = 0)
-  };
-  static const ByteString
-    unknownNonCriticalExtension(unknownNonCriticalExtensionBytes,
-                                sizeof(unknownNonCriticalExtensionBytes));
-  const char* certCN = "Cert With Unknown NonCritical Extension";
-  ByteString cert(CreateCertWithOneExtension(certCN,
-                                             unknownNonCriticalExtension));
-  ASSERT_FALSE(ENCODING_FAILED(cert));
-  Input certInput;
-  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
-  ASSERT_EQ(Success,
-            BuildCertChain(trustDomain, certInput, Now(),
-                           EndEntityOrCA::MustBeEndEntity,
-                           KeyUsage::noParticularKeyUsageRequired,
-                           KeyPurposeId::anyExtendedKeyUsage,
-                           CertPolicyId::anyPolicy,
-                           nullptr/*stapledOCSPResponse*/));
-}
-
-// Tests that an incorrect OID for id-pe-authorityInformationAccess
-// (when marked critical) is detected and that verification fails.
-// (Until bug 1020993 was fixed, the code checked for this OID.)
-TEST_F(pkixcert_extension, WrongOIDCriticalExtension)
-{
-  static const uint8_t wrongOIDCriticalExtensionBytes[] = {
-    0x30, 0x10, // SEQUENCE (length = 16)
-      0x06, 0x09, // OID (length = 9)
-        // 1.3.6.6.1.5.5.7.1.1 (there is an extra "6" that shouldn't be there)
-        0x2b, 0x06, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
-      0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE
-      0x04, 0x00 // OCTET STRING (length = 0)
-  };
-  static const ByteString
-    wrongOIDCriticalExtension(wrongOIDCriticalExtensionBytes,
-                              sizeof(wrongOIDCriticalExtensionBytes));
-  const char* certCN = "Cert With Critical Wrong OID Extension";
-  ByteString cert(CreateCertWithOneExtension(certCN,
-                                             wrongOIDCriticalExtension));
-  ASSERT_FALSE(ENCODING_FAILED(cert));
-  Input certInput;
-  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
-  ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
+  ASSERT_EQ(testcase.expectedResult,
             BuildCertChain(trustDomain, certInput, Now(),
                            EndEntityOrCA::MustBeEndEntity,
                            KeyUsage::noParticularKeyUsageRequired,
                            KeyPurposeId::anyExtendedKeyUsage,
                            CertPolicyId::anyPolicy,
                            nullptr/*stapledOCSPResponse*/));
 }
 
-// Tests that a id-pe-authorityInformationAccess critical extension
-// is detected and that verification succeeds.
-TEST_F(pkixcert_extension, CriticalAIAExtension)
-{
-  // XXX: According to RFC 5280 an AIA that consists of an empty sequence is
-  // not legal, but  we accept it and that is not what we're testing here.
-  static const uint8_t criticalAIAExtensionBytes[] = {
-    0x30, 0x11, // SEQUENCE (length = 17)
-      0x06, 0x08, // OID (length = 8)
-        // 1.3.6.1.5.5.7.1.1
-        0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
-      0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE
-      0x04, 0x02, // OCTET STRING (length = 2)
-        0x30, 0x00, // SEQUENCE (length = 0)
-  };
-  static const ByteString
-    criticalAIAExtension(criticalAIAExtensionBytes,
-                         sizeof(criticalAIAExtensionBytes));
-  const char* certCN = "Cert With Critical AIA Extension";
-  ByteString cert(CreateCertWithOneExtension(certCN, criticalAIAExtension));
-  ASSERT_FALSE(ENCODING_FAILED(cert));
-  Input certInput;
-  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
-  ASSERT_EQ(Success,
-            BuildCertChain(trustDomain, certInput, Now(),
-                           EndEntityOrCA::MustBeEndEntity,
-                           KeyUsage::noParticularKeyUsageRequired,
-                           KeyPurposeId::anyExtendedKeyUsage,
-                           CertPolicyId::anyPolicy,
-                           nullptr/*stapledOCSPResponse*/));
-}
-
-// We know about some id-ce extensions (OID arc 2.5.29), but not all of them.
-// Tests that an unknown id-ce extension is detected and that verification
-// fails.
-TEST_F(pkixcert_extension, UnknownCriticalCEExtension)
-{
-  static const uint8_t unknownCriticalCEExtensionBytes[] = {
-    0x30, 0x0a, // SEQUENCE (length = 10)
-      0x06, 0x03, // OID (length = 3)
-        0x55, 0x1d, 0x37, // 2.5.29.55
-      0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE
-      0x04, 0x00 // OCTET STRING (length = 0)
-  };
-  static const ByteString
-    unknownCriticalCEExtension(unknownCriticalCEExtensionBytes,
-                               sizeof(unknownCriticalCEExtensionBytes));
-  const char* certCN = "Cert With Unknown Critical id-ce Extension";
-  ByteString cert(CreateCertWithOneExtension(certCN,
-                                             unknownCriticalCEExtension));
-  ASSERT_FALSE(ENCODING_FAILED(cert));
-  Input certInput;
-  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
-  ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
-            BuildCertChain(trustDomain, certInput, Now(),
-                           EndEntityOrCA::MustBeEndEntity,
-                           KeyUsage::noParticularKeyUsageRequired,
-                           KeyPurposeId::anyExtendedKeyUsage,
-                           CertPolicyId::anyPolicy,
-                           nullptr/*stapledOCSPResponse*/));
-}
-
-// Tests that a certificate with a known critical id-ce extension (in this case,
-// OID 2.5.29.54, which is id-ce-inhibitAnyPolicy), verifies successfully.
-TEST_F(pkixcert_extension, KnownCriticalCEExtension)
-{
-  static const uint8_t criticalCEExtensionBytes[] = {
-    0x30, 0x0d, // SEQUENCE (length = 13)
-      0x06, 0x03, // OID (length = 3)
-        0x55, 0x1d, 0x36, // 2.5.29.54 (id-ce-inhibitAnyPolicy)
-      0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE
-      0x04, 0x03, // OCTET STRING (length = 3)
-        0x02, 0x01, 0x00, // INTEGER (length = 1, value = 0)
-  };
-  static const ByteString
-    criticalCEExtension(criticalCEExtensionBytes,
-                        sizeof(criticalCEExtensionBytes));
-  const char* certCN = "Cert With Known Critical id-ce Extension";
-  ByteString cert(CreateCertWithOneExtension(certCN, criticalCEExtension));
-  ASSERT_FALSE(ENCODING_FAILED(cert));
-  Input certInput;
-  ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
-  ASSERT_EQ(Success,
-            BuildCertChain(trustDomain, certInput, Now(),
-                           EndEntityOrCA::MustBeEndEntity,
-                           KeyUsage::noParticularKeyUsageRequired,
-                           KeyPurposeId::anyExtendedKeyUsage,
-                           CertPolicyId::anyPolicy,
-                           nullptr/*stapledOCSPResponse*/));
-}
+INSTANTIATE_TEST_CASE_P(pkixcert_extension,
+                        pkixcert_extension,
+                        testing::ValuesIn(EXTENSION_TESTCASES));
 
 // Two subjectAltNames must result in an error.
 TEST_F(pkixcert_extension, DuplicateSubjectAltName)
 {
-  static const uint8_t DER_BYTES[] = {
-    0x30, 22, // SEQUENCE (length = 22)
-      0x06, 3, // OID (length = 3)
-        0x55, 0x1d, 0x11, // 2.5.29.17
-      0x04, 15, // OCTET STRING (length = 15)
-        0x30, 13, // GeneralNames (SEQUENCE) (length = 13)
-          0x82, 11, // [2] (dNSName) (length = 11)
-            'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm'
+  // python DottedOIDToCode.py --tlv id-ce-subjectAltName 2.5.29.17
+  static const uint8_t tlv_id_ce_subjectAltName[] = {
+    0x06, 0x03, 0x55, 0x1d, 0x11
   };
-  static const ByteString DER(DER_BYTES, sizeof(DER_BYTES));
-  static const ByteString extensions[] = { DER, DER, ByteString() };
+
+  ByteString subjectAltName(
+    TLV(der::SEQUENCE,
+        BytesToByteString(tlv_id_ce_subjectAltName) +
+        TLV(der::OCTET_STRING, TLV(der::SEQUENCE, DNSName("example.com")))));
+  static const ByteString extensions[] = { subjectAltName, subjectAltName,
+                                           ByteString() };
   static const char* certCN = "Cert With Duplicate subjectAltName";
   ByteString cert(CreateCertWithExtensions(certCN, extensions));
   ASSERT_FALSE(ENCODING_FAILED(cert));
   Input certInput;
   ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
   ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
             BuildCertChain(trustDomain, certInput, Now(),
                            EndEntityOrCA::MustBeEndEntity,
--- a/security/pkix/test/lib/pkixtestutil.cpp
+++ b/security/pkix/test/lib/pkixtestutil.cpp
@@ -178,25 +178,25 @@ BitString(const ByteString& rawBytes, bo
   prefixed.append(rawBytes);
   if (corrupt) {
     assert(prefixed.length() > 8);
     prefixed[8]++;
   }
   return TLV(der::BIT_STRING, prefixed);
 }
 
-static ByteString
+ByteString
 Boolean(bool value)
 {
   ByteString encodedValue;
   encodedValue.push_back(value ? 0xff : 0x00);
   return TLV(der::BOOLEAN, encodedValue);
 }
 
-static ByteString
+ByteString
 Integer(long value)
 {
   if (value < 0 || value > 127) {
     // TODO: add encoding of larger values
     // It is MUCH more convenient for Integer to be infallible than for it to
     // have "proper" error handling.
     abort();
   }
--- a/security/pkix/test/lib/pkixtestutil.h
+++ b/security/pkix/test/lib/pkixtestutil.h
@@ -106,16 +106,18 @@ const ByteString md2WithRSAEncryption(al
 mozilla::pkix::Time YMDHMS(int16_t year, int16_t month, int16_t day,
                            int16_t hour, int16_t minutes, int16_t seconds);
 
 // e.g. YMDHMS(2016, 12, 31, 1, 23, 45) => 2016-12-31:01:23:45 (GMT)
 mozilla::pkix::Time YMDHMS(int16_t year, int16_t month, int16_t day,
                            int16_t hour, int16_t minutes, int16_t seconds);
 
 ByteString TLV(uint8_t tag, const ByteString& value);
+ByteString Boolean(bool value);
+ByteString Integer(long value);
 
 ByteString CN(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/);
 
 inline ByteString
 CN(const char* value, uint8_t encodingTag = 0x0c /*UTF8String*/)
 {
   return CN(ByteString(reinterpret_cast<const uint8_t*>(value),
                        std::strlen(value)), encodingTag);
--- a/testing/config/mozharness/android_arm_config.py
+++ b/testing/config/mozharness/android_arm_config.py
@@ -28,12 +28,13 @@ config = {
         },
         "xpcshell": {
             "run_filename": "remotexpcshelltests.py",
             "options": ["--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s",
                 "--xre-path=%(xre_path)s", "--testing-modules-dir=%(modules_dir)s",
                 "--apk=%(installer_path)s", "--no-logfiles",
                 "--symbols-path=%(symbols_path)s",
                 "--manifest=tests/xpcshell.ini",
+                "--log-raw=%(raw_log_file)s",
             ],
         },
     }, # end suite_definitions
 }
--- a/testing/config/mozharness/android_panda_config.py
+++ b/testing/config/mozharness/android_panda_config.py
@@ -56,17 +56,18 @@ config = {
         "--deviceIP=%(device_ip)s",
         "--xre-path=../hostutils/xre",
         "--manifest=xpcshell/tests/xpcshell.ini",
         "--build-info-json=xpcshell/mozinfo.json",
         "--testing-modules-dir=modules",
         "--local-lib-dir=../fennec",
         "--apk=../%(apk_name)s",
         "--no-logfiles",
-        "--symbols-path=%(symbols_path)s"
+        "--symbols-path=%(symbols_path)s",
+        "--log-raw=%(raw_log_file)s",
     ],
     "jittest_options": [
         "bin/js",
         "--remote",
         "-j", "1",
         "--deviceTransport=sut",
         "--deviceIP=%(device_ip)s",
         "--localLib=../tests/bin",
--- a/testing/config/mozharness/android_x86_config.py
+++ b/testing/config/mozharness/android_x86_config.py
@@ -28,12 +28,13 @@ config = {
         },
         "xpcshell": {
             "run_filename": "remotexpcshelltests.py",
             "options": ["--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s",
                 "--xre-path=%(xre_path)s", "--testing-modules-dir=%(modules_dir)s",
                 "--apk=%(installer_path)s", "--no-logfiles",
                 "--symbols-path=%(symbols_path)s",
                 "--manifest=tests/xpcshell.ini",
+                "--log-raw=%(raw_log_file)s",
             ],
         },
     }, # end suite_definitions
 }
--- a/testing/config/mozharness/b2g_emulator_config.py
+++ b/testing/config/mozharness/b2g_emulator_config.py
@@ -42,16 +42,17 @@ config = {
         "tests/testing/crashtest/crashtests.list",
     ],
 
     "xpcshell_options": [
         "--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
         "--logdir=%(logcat_dir)s", "--manifest=tests/xpcshell.ini", "--use-device-libs",
         "--testing-modules-dir=%(modules_dir)s", "--symbols-path=%(symbols_path)s",
         "--busybox=%(busybox)s", "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
+        "--log-raw=%(raw_log_file)s",
     ],
 
     "cppunittest_options": [
         "--dm_trans=adb",
         "--symbols-path=%(symbols_path)s",
         "--xre-path=%(xre_path)s",
         "--addEnv", "LD_LIBRARY_PATH=/vendor/lib:/system/lib:/system/b2g",
         "--with-b2g-emulator=%(b2gpath)s",
--- a/testing/config/mozharness/linux_config.py
+++ b/testing/config/mozharness/linux_config.py
@@ -19,17 +19,18 @@ config = {
         "--app=%(app_path)s", "--utility-path=tests/bin",
         "--extra-profile-file=tests/bin/plugins", "--symbols-path=%(symbols_path)s",
         "--certificate-path=tests/certs", "--autorun", "--close-when-done",
         "--console-level=INFO", "--testing-modules-dir=tests/modules",
         "--quiet"
     ],
     "xpcshell_options": [
         "--symbols-path=%(symbols_path)s",
-        "--test-plugin-path=%(test_plugin_path)s"
+        "--test-plugin-path=%(test_plugin_path)s",
+        "--log-raw=%(raw_log_file)s",
     ],
     "cppunittest_options": [
         "--symbols-path=%(symbols_path)s",
         "--xre-path=%(abs_app_dir)s"
     ],
     "jittest_options": [
         "tests/bin/js",
         "--no-slow",
--- a/testing/config/mozharness/mac_config.py
+++ b/testing/config/mozharness/mac_config.py
@@ -18,17 +18,18 @@ config = {
         "--app=%(app_path)s", "--utility-path=tests/bin",
         "--extra-profile-file=tests/bin/plugins", "--symbols-path=%(symbols_path)s",
         "--certificate-path=tests/certs", "--autorun", "--close-when-done",
         "--console-level=INFO", "--testing-modules-dir=tests/modules",
         "--quiet"
     ],
     "xpcshell_options": [
         "--symbols-path=%(symbols_path)s",
-        "--test-plugin-path=%(test_plugin_path)s"
+        "--test-plugin-path=%(test_plugin_path)s",
+        "--log-raw=%(raw_log_file)s",
     ],
     "cppunittest_options": [
         "--symbols-path=%(symbols_path)s",
         "--xre-path=%(abs_app_dir)s"
     ],
     "jittest_options": [
         "tests/bin/js",
         "--no-slow",
--- a/testing/config/mozharness/windows_config.py
+++ b/testing/config/mozharness/windows_config.py
@@ -18,17 +18,18 @@ config = {
         "--app=%(app_path)s", "--utility-path=tests/bin",
         "--extra-profile-file=tests/bin/plugins", "--symbols-path=%(symbols_path)s",
         "--certificate-path=tests/certs", "--autorun", "--close-when-done",
         "--console-level=INFO", "--testing-modules-dir=tests/modules",
         "--quiet"
     ],
     "xpcshell_options": [
         "--symbols-path=%(symbols_path)s",
-        "--test-plugin-path=%(test_plugin_path)s"
+        "--test-plugin-path=%(test_plugin_path)s",
+        "--log-raw=%(raw_log_file)s",
     ],
     "cppunittest_options": [
         "--symbols-path=%(symbols_path)s",
         "--xre-path=%(abs_app_dir)s"
     ],
     "jittest_options": [
         "tests/bin/js",
         "--no-slow",
--- a/testing/mochitest/android23.json
+++ b/testing/mochitest/android23.json
@@ -1,12 +1,6 @@
 {
 "runtests": {},
 "excludetests": {
-  "dom/html/test/test_bug659743.xml": "Android 2.3 aws only; bug 1031103",
-  "docshell/test/navigation/test_reserved.html": "too slow on Android 2.3 aws only; bug 1030403",
-  "dom/canvas/test/webgl-conformance": "bug 865443 - separate suite -- mochitest-gl",
-  "dom/canvas/test/webgl-mochitest/test_no_arr_points.html": "Android 2.3 aws only; bug 1030942",
-  "dom/media/tests/mochitest": "Android 2.3 only; bug 981881",
-  "layout/style/test/test_media_queries.html": "Android 2.3 aws only; bug 1030419",
-  "layout/style/test/test_transitions_cancel_near_end.html": "Android 2.3 aws only; bug 1030432"
+  "dom/canvas/test/webgl-conformance": "bug 865443 - separate suite -- mochitest-gl"
   }
 }
--- a/testing/mochitest/mach_commands.py
+++ b/testing/mochitest/mach_commands.py
@@ -87,17 +87,17 @@ class MochitestRunner(MozbuildObject):
     to hook up result parsing, etc.
     """
 
     def get_webapp_runtime_path(self):
         import mozinfo
         appname = 'webapprt-stub' + mozinfo.info.get('bin_suffix', '')
         if sys.platform.startswith('darwin'):
             appname = os.path.join(self.distdir, self.substs['MOZ_MACBUNDLE_NAME'],
-            'Contents', 'MacOS', appname)
+            'Contents', 'Resources', appname)
         else:
             appname = os.path.join(self.distdir, 'bin', appname)
         return appname
 
     def __init__(self, *args, **kwargs):
         MozbuildObject.__init__(self, *args, **kwargs)
 
         # TODO Bug 794506 remove once mach integrates with virtualenv.
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -109,17 +109,17 @@ class ADBCommand(object):
     restriction calling ADBCommand's constructor will raise a
     NonImplementedError exception.
 
     ::
 
        from mozdevice import ADBCommand
 
        try:
-           adbcommand = ADBCommand(...)
+           adbcommand = ADBCommand()
        except NotImplementedError:
            print "ADBCommand can not be instantiated."
 
     """
 
     def __init__(self,
                  adb='adb',
                  logger_name='adb',
@@ -275,17 +275,17 @@ class ADBCommand(object):
 class ADBHost(ADBCommand):
     """ADBHost provides a basic interface to adb host commands
     which do not target a specific device.
 
     ::
 
        from mozdevice import ADBHost
 
-       adbhost = ADBHost(...)
+       adbhost = ADBHost()
        adbhost.start_server()
 
     """
     def __init__(self,
                  adb='adb',
                  logger_name='adb',
                  timeout=300,
                  verbose=False):
@@ -437,17 +437,17 @@ class ADBDevice(ADBCommand):
 
     Android specific features such as Application management are not
     included but are provided via the ADBAndroid interface.
 
     ::
 
        from mozdevice import ADBDevice
 
-       adbdevice = ADBDevice(...)
+       adbdevice = ADBDevice()
        print adbdevice.list_files("/mnt/sdcard")
        if adbdevice.process_exist("org.mozilla.fennec"):
            print "Fennec is running"
 
     """
 
     def __init__(self,
                  device=None,
deleted file mode 100644
--- a/testing/mozharness/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-mozharness.json is a manifest file that is currently only used on try.
-It allows you to lock mozharness to a repository and a revision.
deleted file mode 100644
--- a/testing/mozharness/mozharness.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "repo": "http://hg.mozilla.org/build/mozharness",
-    "revision": "production"
-}
deleted file mode 100644
--- a/testing/mozharness/repository_from_code.py
+++ /dev/null
@@ -1,121 +0,0 @@
-#! /usr/bin/env 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/.
-
-#
-# Script name:   repository_manifest.py
-# Purpose:       Reads from a json file a repository and revision to use.
-#                If none is found we fall back to the default values.
-# Author(s):     Zambrano Gasparnian, Armen <armenzg@mozilla.com>
-# Target:        Python 2.7.x
-#
-from optparse import OptionParser
-import json
-import re
-import urllib2
-import urlparse
-import sys
-import os
-
-def main():
-    '''
-    Determine which repository and revision mozharness.json indicates.
-    If none is found we fall back to the default repository
-    '''
-    parser = OptionParser()
-    parser.add_option("--repository-manifest-url", dest="repository_manifest_url", type="string",
-                      help="It indicates from where to download the talos.json file.")
-    (options, args) = parser.parse_args()
-
-    # 1) check that the url was passed
-    if options.repository_manifest_url == None:
-        print "You need to specify --repository-manifest-url."
-        sys.exit(1)
-
-    # 2) try to download the talos.json file
-    try:
-        jsonFilename = download_file(options.talos_json_url)
-    except Exception, e:
-        print "ERROR: We tried to download the talos.json file but something failed."
-        print "ERROR: %s" % str(e)
-        sys.exit(1)
-
-    # 3) download the necessary files
-    print "INFO: talos.json URL: %s" % options.talos_json_url
-    try:
-        key = 'talos.zip'
-        entity = get_value(jsonFilename, key)
-        if passesRestrictions(options.talos_json_url, entity["url"]):
-            # the key is at the same time the filename e.g. talos.zip
-            print "INFO: Downloading %s as %s" % (entity["url"], os.path.join(entity["path"], key))
-            download_file(entity["url"], entity["path"], key)
-        else:
-            print "ERROR: You have tried to download a file " + \
-                  "from: %s " % entity["url"] + \
-                  "which is a location different than http://talos-bundles.pvt.build.mozilla.org/"
-            print "ERROR: This is only allowed for the certain branches."
-            sys.exit(1)
-    except Exception, e:
-        print "ERROR: %s" % str(e)
-        sys.exit(1)
-
-def passesRestrictions(talosJsonUrl, fileUrl):
-    '''
-    Only certain branches are exempted from having to host their downloadable files
-    in talos-bundles.pvt.build.mozilla.org
-    '''
-    if talosJsonUrl.startswith("http://hg.mozilla.org/try/") or \
-       talosJsonUrl.startswith("https://hg.mozilla.org/try/") or \
-       talosJsonUrl.startswith("http://hg.mozilla.org/projects/pine/") or \
-       talosJsonUrl.startswith("https://hg.mozilla.org/projects/pine/") or \
-       talosJsonUrl.startswith("http://hg.mozilla.org/projects/ash/") or \
-       talosJsonUrl.startswith("https://hg.mozilla.org/projects/ash/"):
-        return True
-    else:
-        p = re.compile('^http://talos-bundles.pvt.build.mozilla.org/')
-        m = p.match(fileUrl)
-        if m == None:
-            return False
-        return True
-
-def get_filename_from_url(url):
-    '''
-    This returns the filename of the file we're trying to download
-    '''
-    parsed = urlparse.urlsplit(url.rstrip('/'))
-    if parsed.path != '':
-        return parsed.path.rsplit('/', 1)[-1]
-    else:
-        print "ERROR: We were trying to download a file from %s " + \
-              "but the URL seems to be incorrect."
-        sys.exit(1)
-
-def download_file(url, path="", saveAs=None):
-    '''
-    It downloads a file from URL to the indicated path
-    '''
-    req = urllib2.Request(url)
-    f = urllib2.urlopen(req)
-    if path != "" and not os.path.isdir(path):
-        try:
-            os.makedirs(path)
-            print "INFO: directory %s created" % path
-        except Exception, e:
-            print "ERROR: %s" % str(e)
-            sys.exit(1)
-    filename = saveAs if saveAs else get_filename_from_url(url)
-    local_file = open(os.path.join(path, filename), 'wb')
-    local_file.write(f.read())
-    local_file.close()
-    return filename
-
-def get_value(json_filename, key):
-    '''
-    It loads up a JSON file and returns the value for the given string
-    '''
-    f = open(json_filename, 'r')
-    return json.load(f)[key]
-
-if __name__ == '__main__':
-    main()
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -164,17 +164,17 @@ ifeq (powerpc,$(TARGET_CPU))
 	$(RUN_MOCHITEST) --setpref=dom.ipc.plugins.enabled.ppc.test.plugin=false $(IPCPLUGINS_PATH_ARG)
 endif
 else
 	$(RUN_MOCHITEST) --setpref=dom.ipc.plugins.enabled=false --test-path=dom/plugins/test
 endif
 	$(CHECK_TEST_ERROR)
 
 ifeq ($(OS_ARCH),Darwin)
-webapprt_stub_path = $(TARGET_DIST)/$(MOZ_MACBUNDLE_NAME)/Contents/MacOS/webapprt-stub$(BIN_SUFFIX)
+webapprt_stub_path = $(TARGET_DIST)/$(MOZ_MACBUNDLE_NAME)/Contents/Resources/webapprt-stub$(BIN_SUFFIX)
 endif
 ifeq ($(OS_ARCH),WINNT)
 webapprt_stub_path = $(TARGET_DIST)/bin/webapprt-stub$(BIN_SUFFIX)
 endif
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 webapprt_stub_path = $(TARGET_DIST)/bin/webapprt-stub$(BIN_SUFFIX)
 endif
 
--- a/toolkit/webapps/MacNativeApp.js
+++ b/toolkit/webapps/MacNativeApp.js
@@ -217,17 +217,18 @@ NativeApp.prototype = {
                           { unixMode: PERMS_DIRECTORY, ignoreExisting: true });
 
     yield OS.File.makeDir(OS.Path.join(aDir, this.resourcesDir),
                           { unixMode: PERMS_DIRECTORY, ignoreExisting: true });
   }),
 
   _copyPrebuiltFiles: function(aDir) {
     let destDir = getFile(aDir, this.macOSDir);
-    let stub = getFile(this.runtimeFolder, "webapprt-stub");
+    let stub = getFile(OS.Path.join(OS.Path.dirname(this.runtimeFolder),
+                                    "Resources"), "webapprt-stub");
     stub.copyTo(destDir, "webapprt");
   },
 
   _createConfigFiles: function(aDir) {
     // ${ProfileDir}/webapp.json
     yield writeToFile(OS.Path.join(aDir, this.configJson),
                       JSON.stringify(this.webappJson));
 
--- a/toolkit/webapps/tests/test_webapp_runtime_executable_update.xul
+++ b/toolkit/webapps/tests/test_webapp_runtime_executable_update.xul
@@ -89,17 +89,17 @@ let runTest = Task.async(function*() {
   yield nativeApp.install(app, manifest);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
 
   let fakeInstallDir;
   if (MAC) {
-    fakeInstallDir = getFile(testAppInfo.installPath, "Contents", "MacOS");
+    fakeInstallDir = getFile(testAppInfo.installPath, "Contents", "Resources");
   } else {
     fakeInstallDir = getFile(OS.Constants.Path.profileDir, "fakeInstallDir");
     fakeInstallDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
   }
 
   let fakeAppIniFile = fakeInstallDir.clone();
   fakeAppIniFile.append("application.ini");
 
--- a/webapprt/mac/webapprt.mm
+++ b/webapprt/mac/webapprt.mm
@@ -161,17 +161,17 @@ main(int argc, char **argv)
       NSLog(@"### This Application has an old webrt. Updating it.");
       NSLog(@"### My webapprt path: %@", myWebRTPath);
 
       NSFileManager* fileClerk = [[NSFileManager alloc] init];
       NSError *errorDesc = nil;
 
       //we know the firefox path, so copy the new webapprt here
       NSString *newWebRTPath =
-        [NSString stringWithFormat: @"%@%s%s", firefoxPath, APP_MACOS_PATH,
+        [NSString stringWithFormat: @"%@%s%s", firefoxPath, APP_RESOURCES_PATH,
                                                WEBAPPRT_EXECUTABLE];
       NSLog(@"### Firefox webapprt path: %@", newWebRTPath);
       if (![fileClerk fileExistsAtPath:newWebRTPath]) {
         NSString* msg = [NSString stringWithFormat: @"This version of Firefox (%@) cannot run web applications, because it is not recent enough or damaged", firefoxVersion];
         @throw MakeException(@"Missing Web Runtime Files", msg);
       }
 
       [fileClerk removeItemAtPath: myWebRTPath error: &errorDesc];