merge m-c to inbound on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Fri, 20 Jun 2014 14:02:54 -0700
changeset 190010 6da364bc0e3ec25e0783c25f6f186ba572cb6cf4
parent 190009 724d46a1b00a58fff7b846193c082759c4d43eac (current diff)
parent 189838 776f6d341b3f013672a861a4ee0283c120e3e46f (diff)
child 190011 367d902bd3b09a319726455339c12a2b75165e0f
push id8288
push userryanvm@gmail.com
push dateMon, 23 Jun 2014 14:59:00 +0000
treeherderb2g-inbound@c65bf5a0595c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone33.0a1
merge m-c to inbound on a CLOSED TREE
browser/app/profile/firefox.js
dom/browser-element/BrowserElementParent.jsm
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd5065ced020014df5fd45259fba1ac32d65673b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3326b51017252e09ccdd715dec6c5e12a7d1ecfe"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="cc67f31dc638c0b7edba3cf7e3d87cadf0ed52bf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="bd5065ced020014df5fd45259fba1ac32d65673b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="bd5065ced020014df5fd45259fba1ac32d65673b"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd5065ced020014df5fd45259fba1ac32d65673b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3326b51017252e09ccdd715dec6c5e12a7d1ecfe"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="cc67f31dc638c0b7edba3cf7e3d87cadf0ed52bf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="bd5065ced020014df5fd45259fba1ac32d65673b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "dcb55fbcaa9bd33e662a2c5e99cdb7e4c9d7ad51", 
+    "revision": "387f4c0123a7e82eae4c83f88f73e81f907c00e2", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd5065ced020014df5fd45259fba1ac32d65673b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd5065ced020014df5fd45259fba1ac32d65673b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="cc67f31dc638c0b7edba3cf7e3d87cadf0ed52bf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="bd5065ced020014df5fd45259fba1ac32d65673b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd5065ced020014df5fd45259fba1ac32d65673b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -642,20 +642,16 @@ pref("network.protocol-handler.expose.nn
 pref("accessibility.typeaheadfind", false);
 pref("accessibility.typeaheadfind.timeout", 5000);
 pref("accessibility.typeaheadfind.linksonly", false);
 pref("accessibility.typeaheadfind.flashBar", 1);
 
 // plugin finder service url
 pref("pfs.datasource.url", "https://pfs.mozilla.org/plugins/PluginFinderService.php?mimetype=%PLUGIN_MIMETYPE%&appID=%APP_ID%&appVersion=%APP_VERSION%&clientOS=%CLIENT_OS%&chromeLocale=%CHROME_LOCALE%&appRelease=%APP_RELEASE%");
 
-// by default we show an infobar message when pages require plugins that are blocked, or are outdated
-pref("plugins.hide_infobar_for_blocked_plugin", false);
-pref("plugins.hide_infobar_for_outdated_plugin", false);
-
 pref("plugins.update.url", "https://www.mozilla.org/%LOCALE%/plugincheck/");
 pref("plugins.update.notifyUser", false);
 
 pref("plugins.click_to_play", true);
 
 pref("plugins.hideMissingPluginsNotification", false);
 
 pref("plugin.default.state", 1);
@@ -1337,16 +1333,18 @@ pref("devtools.scratchpad.showTrailingSp
 pref("devtools.scratchpad.enableCodeFolding", true);
 pref("devtools.scratchpad.enableAutocompletion", true);
 
 // Enable the Style Editor.
 pref("devtools.styleeditor.enabled", true);
 pref("devtools.styleeditor.source-maps-enabled", false);
 pref("devtools.styleeditor.autocompletion-enabled", true);
 pref("devtools.styleeditor.showMediaSidebar", true);
+pref("devtools.styleeditor.mediaSidebarWidth", 238);
+pref("devtools.styleeditor.navSidebarWidth", 245);
 
 // Enable the Shader Editor.
 pref("devtools.shadereditor.enabled", false);
 
 // Enable the Canvas Debugger.
 pref("devtools.canvasdebugger.enabled", false);
 
 // Enable the Web Audio Editor
--- a/browser/base/content/test/general/browser_offlineQuotaNotification.js
+++ b/browser/base/content/test/general/browser_offlineQuotaNotification.js
@@ -33,21 +33,21 @@ function checkPreferences(prefsWin) {
       // all good, we are done.
       prefsWin.close();
       finish();
     });
   });
 }
 // Same as the other one, but for in-content preferences
 function checkInContentPreferences(win) {
-  let sel = win.history.state;
   let doc = win.document;
+  let sel = doc.getElementById("categories").selectedItems[0].id;
   let tab = doc.getElementById("advancedPrefs").selectedTab.id;
-  is(gBrowser.currentURI.spec, "about:preferences", "about:preferences loaded");
-  is(sel, "paneAdvanced", "Advanced pane was selected");
+  is(gBrowser.currentURI.spec, "about:preferences#advanced", "about:preferences loaded");
+  is(sel, "category-advanced", "Advanced pane was selected");
   is(tab, "networkTab", "Network tab is selected");
   // all good, we are done.
   win.close();
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
@@ -70,17 +70,19 @@ function test() {
             checkPreferences(aSubject);
           });
         }
         PopupNotifications.panel.firstElementChild.button.click();
         if (Services.prefs.getBoolPref("browser.preferences.inContent")) {
           let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
           newTabBrowser.addEventListener("Initialized", function PrefInit() {
             newTabBrowser.removeEventListener("Initialized", PrefInit, true);
-            checkInContentPreferences(newTabBrowser.contentWindow);
+            executeSoon(function() {
+              checkInContentPreferences(newTabBrowser.contentWindow);
+            })
           }, true);
         }
       });
     };
     Services.prefs.setIntPref("offline-apps.quota.warn", 1);
 
     // Click the notification panel's "Allow" button.  This should kick
     // off updates which will call our oncached handler above.
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -483,42 +483,46 @@ function openPreferences(paneID, extraAr
 {
   function switchToAdvancedSubPane(doc) {
     if (extraArgs && extraArgs["advancedTab"]) {
       let advancedPaneTabs = doc.getElementById("advancedPrefs");
       advancedPaneTabs.selectedTab = doc.getElementById(extraArgs["advancedTab"]);
     }
   }
 
+  // This function is duplicated from preferences.js.
+  function internalPrefCategoryNameToFriendlyName(aName) {
+    return (aName || "").replace(/^pane./, function(toReplace) { return toReplace[4].toLowerCase(); });
+  }
+
   if (getBoolPref("browser.preferences.inContent")) {
     let win = Services.wm.getMostRecentWindow("navigator:browser");
     if (!win) {
       return;
     }
 
-    let newLoad = !win.switchToTabHavingURI("about:preferences", true);
+    let friendlyCategoryName = internalPrefCategoryNameToFriendlyName(paneID);
+    let preferencesURL = "about:preferences" +
+                         (friendlyCategoryName ? "#" + friendlyCategoryName : "");
+    let newLoad = !win.switchToTabHavingURI(preferencesURL, true, {ignoreFragment: true});
     let browser = win.gBrowser.selectedBrowser;
 
-    function switchToPane() {
-      if (paneID) {
-        browser.contentWindow.selectCategory(paneID);
-      }
-      switchToAdvancedSubPane(browser.contentDocument);
-    }
-
     if (newLoad) {
       Services.obs.addObserver(function advancedPaneLoadedObs(prefWin, topic, data) {
         if (prefWin != browser.contentWindow) {
           return;
         }
         Services.obs.removeObserver(advancedPaneLoadedObs, "advanced-pane-loaded");
-        switchToPane();
+        switchToAdvancedSubPane(browser.contentDocument);
       }, "advanced-pane-loaded", false);
     } else {
-      switchToPane();
+      if (paneID) {
+        browser.contentWindow.gotoPref(paneID);
+      }
+      switchToAdvancedSubPane(browser.contentDocument);
     }
   } else {
     var instantApply = getBoolPref("browser.preferences.instantApply", false);
     var features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal");
 
     var win = Services.wm.getMostRecentWindow("Browser:Preferences");
     if (win) {
       win.focus();
--- a/browser/components/places/tests/browser/browser_drag_bookmarks_on_toolbar.js
+++ b/browser/components/places/tests/browser/browser_drag_bookmarks_on_toolbar.js
@@ -133,16 +133,26 @@ function getExpectedDataForPlacesNode(aN
     var wrappedFlavor = aFlavor + ": " +
                         PlacesUtils.wrapNode(aNode, aFlavor);
     wrappedNode.push(wrappedFlavor);
   });
 
   return [wrappedNode];
 }
 
+function afterToolbarTransition(callback) {
+  function listener(event) {
+    if (event.propertyName == "max-height") {
+      toolbar.removeEventListener("transitionend", listener);
+      callback();
+    }
+  }
+  toolbar.addEventListener("transitionend", listener);
+}
+
 var gTests = [
 
 //------------------------------------------------------------------------------
 
   {
     desc: "Drag a folder on toolbar",
     run: function() {
       // Create a test folder to be dragged.
@@ -229,27 +239,32 @@ function nextTest() {
     var test = gTests.shift();
     waitForFocus(function() {
       info("Start of test: " + test.desc);
       test.run();
     });
   }
   else {
     // Collapse the personal toolbar if needed.
-    if (wasCollapsed)
+    if (wasCollapsed) {
       setToolbarVisibility(toolbar, false);
-    finish();
+      afterToolbarTransition(finish);
+    } else {
+      finish();
+    }
   }
 }
 
 let toolbar = document.getElementById("PersonalToolbar");
 let wasCollapsed = toolbar.collapsed;
 
 function test() {
   waitForExplicitFinish();
 
   // Uncollapse the personal toolbar if needed.
-  if (wasCollapsed)
+  if (wasCollapsed) {
     setToolbarVisibility(toolbar, true);
-
-  nextTest();
+    afterToolbarTransition(nextTest);
+  } else {
+    nextTest();
+  }
 }
 
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -66,19 +66,16 @@ var gAdvancedPane = {
     this.initSubmitCrashes();
 #endif
     this.initTelemetry();
 #ifdef MOZ_SERVICES_HEALTHREPORT
     this.initSubmitHealthReport();
 #endif
     this.updateActualCacheSize();
     this.updateActualAppCacheSize();
-
-    // Notify observers that the UI is now ready
-    Services.obs.notifyObservers(window, "advanced-pane-loaded", null);
   },
 
   /**
    * Stores the identity of the current tab in preferences so that the selected
    * tab can be persisted between openings of the preferences window.
    */
   tabSelectionChanged: function ()
   {
--- a/browser/components/preferences/in-content/preferences.js
+++ b/browser/components/preferences/in-content/preferences.js
@@ -7,16 +7,18 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
+let gLastHash = "";
+
 addEventListener("DOMContentLoaded", function onLoad() {
   removeEventListener("DOMContentLoaded", onLoad);
   init_all();
 });
 
 function init_all() {
   document.documentElement.instantApply = true;
   gMainPane.init();
@@ -37,31 +39,55 @@ function init_all() {
     if (event.keyCode == KeyEvent.DOM_VK_TAB) {
       categories.setAttribute("keyboard-navigation", "true");
     }
   });
   categories.addEventListener("mousedown", function() {
     this.removeAttribute("keyboard-navigation");
   });
 
-  if (document.getElementById("category-general").selected) {
-    gotoPref("paneGeneral");
-  }
+  window.addEventListener("hashchange", onHashChange);
+  gotoPref();
+
+  // Wait until initialization of all preferences are complete before
+  // notifying observers that the UI is now ready.
+  Services.obs.notifyObservers(window, "advanced-pane-loaded", null);
+}
+
+function onHashChange() {
+  gotoPref();
 }
 
-function selectCategory(name) {
+function gotoPref(aCategory) {
   let categories = document.getElementById("categories");
-  let item = categories.querySelector(".category[value=" + name + "]");
+  const kDefaultCategoryInternalName = categories.firstElementChild.value;
+  let hash = document.location.hash;
+  let category = aCategory || hash.substr(1) || kDefaultCategoryInternalName;
+  category = friendlyPrefCategoryNameToInternalName(category);
+
+  // Updating the hash (below) or changing the selected category
+  // will re-enter gotoPref.
+  if (gLastHash == category)
+    return;
+  let item = categories.querySelector(".category[value=" + category + "]");
+  if (!item) {
+    category = kDefaultCategoryInternalName;
+    item = categories.querySelector(".category[value=" + category + "]");
+  }
+
+  let newHash = internalPrefCategoryNameToFriendlyName(category);
+  if (gLastHash || category != kDefaultCategoryInternalName) {
+    document.location.hash = newHash;
+  }
+  // Need to set the gLastHash before setting categories.selectedItem since
+  // the categories 'select' event will re-enter the gotoPref codepath.
+  gLastHash = category;
   categories.selectedItem = item;
-  gotoPref(name);
-}
-
-function gotoPref(page) {
-  window.history.replaceState(page, document.title);
-  search(page, "data-category");
+  window.history.replaceState(category, document.title);
+  search(category, "data-category");
 }
 
 function search(aQuery, aAttribute) {
   let elements = document.getElementById("mainPrefPane").children;
   for (let element of elements) {
     let attributeValue = element.getAttribute(aAttribute);
     element.hidden = (attributeValue != aQuery);
   }
@@ -69,8 +95,19 @@ function search(aQuery, aAttribute) {
 
 function helpButtonCommand() {
   let pane = history.state;
   let categories = document.getElementById("categories");
   let helpTopic = categories.querySelector(".category[value=" + pane + "]")
                             .getAttribute("helpTopic");
   openHelpLink(helpTopic);
 }
+
+function friendlyPrefCategoryNameToInternalName(aName) {
+  if (aName.startsWith("pane"))
+    return aName;
+  return "pane" + aName.substring(0,1).toUpperCase() + aName.substr(1);
+}
+
+// This function is duplicated inside of utilityOverlay.js's openPreferences.
+function internalPrefCategoryNameToFriendlyName(aName) {
+  return (aName || "").replace(/^pane./, function(toReplace) { return toReplace[4].toLowerCase(); });
+}
--- a/browser/components/preferences/in-content/tests/browser_bug1020245_openPreferences_to_paneContent.js
+++ b/browser/components/preferences/in-content/tests/browser_bug1020245_openPreferences_to_paneContent.js
@@ -1,25 +1,59 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-add_task(function test() {
-  waitForExplicitFinish();
+add_task(function() {
+  let prefs = yield openPreferencesViaOpenPreferencesAPI("paneContent");
+  is(prefs.selectedPane, "paneContent", "Content pane was selected");
+  prefs = yield openPreferencesViaOpenPreferencesAPI("advanced", "updateTab");
+  is(prefs.selectedPane, "paneAdvanced", "Advanced pane was selected");
+  is(prefs.selectedAdvancedTab, "updateTab", "The update tab within the advanced prefs should be selected");
+  prefs = yield openPreferencesViaHash("privacy");
+  is(prefs.selectedPane, "panePrivacy", "Privacy pane is selected when hash is 'privacy'");
+  prefs = yield openPreferencesViaOpenPreferencesAPI("nonexistant-category");
+  is(prefs.selectedPane, "paneGeneral", "General pane is selected by default when a nonexistant-category is requested");
+  prefs = yield openPreferencesViaHash("nonexistant-category");
+  is(prefs.selectedPane, "paneGeneral", "General pane is selected when hash is a nonexistant-category");
+  prefs = yield openPreferencesViaHash();
+  is(prefs.selectedPane, "paneGeneral", "General pane is selected by default");
+});
+
+function openPreferencesViaOpenPreferencesAPI(aPane, aAdvancedTab) {
   let deferred = Promise.defer();
   gBrowser.selectedTab = gBrowser.addTab("about:blank");
-  openPreferences("paneContent");
-  let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+  openPreferences(aPane, aAdvancedTab ? {advancedTab: aAdvancedTab} : undefined);
+  let newTabBrowser = gBrowser.selectedBrowser;
 
   newTabBrowser.addEventListener("Initialized", function PrefInit() {
     newTabBrowser.removeEventListener("Initialized", PrefInit, true);
     newTabBrowser.contentWindow.addEventListener("load", function prefLoad() {
       newTabBrowser.contentWindow.removeEventListener("load", prefLoad);
-      let sel = gBrowser.contentWindow.history.state;
-      is(sel, "paneContent", "Content pane was selected");
-      deferred.resolve();
+      let win = gBrowser.contentWindow;
+      let selectedPane = win.history.state;
+      let doc = win.document;
+      let selectedAdvancedTab = aAdvancedTab && doc.getElementById("advancedPrefs").selectedTab.id;
       gBrowser.removeCurrentTab();
+      deferred.resolve({selectedPane: selectedPane, selectedAdvancedTab: selectedAdvancedTab});
     });
   }, true);
 
-  yield deferred.promise;
+  return deferred.promise;
+}
+
+function openPreferencesViaHash(aPane) {
+  let deferred = Promise.defer();
+  gBrowser.selectedTab = gBrowser.addTab("about:preferences" + (aPane ? "#" + aPane : ""));
+  let newTabBrowser = gBrowser.selectedBrowser;
 
-  finish();
-});
+  newTabBrowser.addEventListener("Initialized", function PrefInit() {
+    newTabBrowser.removeEventListener("Initialized", PrefInit, true);
+    newTabBrowser.contentWindow.addEventListener("load", function prefLoad() {
+      newTabBrowser.contentWindow.removeEventListener("load", prefLoad);
+      let win = gBrowser.contentWindow;
+      let selectedPane = win.history.state;
+      gBrowser.removeCurrentTab();
+      deferred.resolve({selectedPane: selectedPane});
+    });
+  }, true);
+
+  return deferred.promise;
+}
--- a/browser/components/preferences/in-content/tests/browser_bug410900.js
+++ b/browser/components/preferences/in-content/tests/browser_bug410900.js
@@ -32,17 +32,17 @@ function test() {
   Services.obs.addObserver(observer, "app-handler-pane-loaded", false);
 
   gBrowser.selectedTab = gBrowser.addTab("about:preferences");
 }
 
 function runTest(win) {
   win.gotoPref("applications");
   var sel = win.history.state;
-  ok(sel == "applications", "Specified pane was opened");
+  is(sel, "paneApplications", "Specified pane was opened");
 
   var rbox = win.document.getElementById("handlersView");
   ok(rbox, "handlersView is present");
 
   var items = rbox && rbox.getElementsByTagName("richlistitem");
   ok(items && items.length > 0, "App handler list populated");
 
   var handlerAdded = false;
--- a/browser/components/preferences/in-content/tests/browser_bug731866.js
+++ b/browser/components/preferences/in-content/tests/browser_bug731866.js
@@ -21,27 +21,16 @@ function runTest(win) {
     let attributeValue = element.getAttribute("data-category");
     if (attributeValue == "paneGeneral") {
       is_element_visible(element, "General elements should be visible");
     } else {
       is_element_hidden(element, "Non-General elements should be hidden");
     }
   }
 
-  //Test if tabs pane is opened correctly
-  win.gotoPref("paneTabs");
-  for (let element of elements) {
-    let attributeValue = element.getAttribute("data-category");
-    if (attributeValue == "paneTabs") {
-      is_element_visible(element, "Tab elements should be visible");
-    } else {
-      is_element_hidden(element, "Non-Tab elements should be hidden");
-    }
-  }
-
   //Test if content pane is opened correctly
   win.gotoPref("paneContent");
   for (let element of elements) {
     let attributeValue = element.getAttribute("data-category");
     if (attributeValue == "paneContent") {
       is_element_visible(element, "Content elements should be visible");
     } else {
       is_element_hidden(element, "Non-Content elements should be hidden");
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -712,12 +712,15 @@ DocShellCapabilitiesListener.init();
 PrivacyListener.init();
 
 addEventListener("unload", () => {
   // Remove all registered nsIObservers.
   PageStyleListener.uninit();
   SessionStorageListener.uninit();
   SessionHistoryListener.uninit();
 
+  // Remove progress listeners.
+  gContentRestore.resetRestore();
+
   // We don't need to take care of any gFrameTree observers as the gFrameTree
   // will die with the content script. The same goes for the privacy transition
   // observer that will die with the docShell when the tab is closed.
 });
--- a/browser/components/sessionstore/src/ContentRestore.jsm
+++ b/browser/components/sessionstore/src/ContentRestore.jsm
@@ -171,17 +171,17 @@ ContentRestoreInternal.prototype = {
     this._historyListener = null;
 
     // We're about to start a load. This listener will be called when the load
     // has finished getting everything from the network.
     let progressListener = new ProgressListener(this.docShell, () => {
       // Call resetRestore to reset the state back to normal. The data needed
       // for restoreDocument (which hasn't happened yet) will remain in
       // _restoringDocument.
-      this.resetRestore(this.docShell);
+      this.resetRestore();
 
       finishCallback();
     });
     this._progressListener = progressListener;
 
     // Reset the current URI to about:blank. We changed it above for
     // switch-to-tab, but now it must go back to the correct value before the
     // load happens.
@@ -356,17 +356,20 @@ function HistoryListener(docShell, callb
 }
 HistoryListener.prototype = {
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsISHistoryListener,
     Ci.nsISupportsWeakReference
   ]),
 
   uninstall: function () {
-    this.webNavigation.sessionHistory.removeSHistoryListener(this);
+    let shistory = this.webNavigation.sessionHistory;
+    if (shistory) {
+      shistory.removeSHistoryListener(this);
+    }
   },
 
   OnHistoryNewEntry: function(newURI) {},
   OnHistoryGoBack: function(backURI) { return true; },
   OnHistoryGoForward: function(forwardURI) { return true; },
   OnHistoryGotoIndex: function(index, gotoURI) { return true; },
   OnHistoryPurge: function(numEntries) { return true; },
   OnHistoryReplaceEntry: function(index) {},
--- a/browser/components/sessionstore/test/browser_911547_sample.html
+++ b/browser/components/sessionstore/test/browser_911547_sample.html
@@ -1,18 +1,19 @@
 <!DOCTYPE html>
 <html>
   <head>
+    <meta charset="utf-8">
     <title>Test 911547</title>
   </head>
 <body>
 
   <!--
    this element gets modified by an injected script;
    that script should be blocked by CSP.
    Inline scripts can modify it, but not data uris.
   -->
   <input type="text" id="test_id" value="ok">
 
-  <a id="test_data_link" href="data:text/html,<input type='text' id='test_id2' value='ok'/> <script>document.getElementById('test_id2').value = 'fail';</script>">Test Link</a>
+  <a id="test_data_link" href="data:text/html;charset=utf-8,<input type='text' id='test_id2' value='ok'/> <script>document.getElementById('test_id2').value = 'fail';</script>">Test Link</a>
 
 </body>
 </html>
--- a/browser/devtools/framework/connect/connect.xhtml
+++ b/browser/devtools/framework/connect/connect.xhtml
@@ -24,17 +24,17 @@
           <span>&host;</span>
           <input required="required" class="devtools-textinput" id="host" type="text"></input>
         </label>
         <label>
           <span>&port;</span>
           <input required="required" class="devtools-textinput" id="port" type="number" pattern="\d+"></input>
         </label>
         <label>
-          <input class="devtools-toolbarbutton" id="submit" type="submit" value="&connect;"></input>
+          <input class="devtools-toolbarbutton" id="submit" standalone="true" type="submit" value="&connect;"></input>
         </label>
       </form>
       <p class="error-message error-timeout">&errorTimeout;</p>
       <p class="error-message error-refused">&errorRefused;</p>
       <p class="error-message error-unexpected">&errorUnexpected;</p>
     </section>
     <section id="actors-list">
       <p>&availableTabs;</p>
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -52,18 +52,16 @@ DevTools.prototype = {
   set testing(state) {
     this._testing = state;
 
     if (state) {
       // dom.send_after_paint_to_content is set to true (non-default) in
       // testing/profiles/prefs_general.js so lets set it to the same as it is
       // in a default browser profile for the duration of the test.
       Services.prefs.setBoolPref("dom.send_after_paint_to_content", false);
-    } else {
-      Services.prefs.setBoolPref("dom.send_after_paint_to_content", true);
     }
   },
 
   /**
    * Register a new developer tool.
    *
    * A definition is a light object that holds different information about a
    * developer tool. This object is not supposed to have any operational code.
--- a/browser/devtools/inspector/test/browser.ini
+++ b/browser/devtools/inspector/test/browser.ini
@@ -3,16 +3,18 @@ skip-if = e10s # Bug ?????? - devtools t
 subsuite = devtools
 support-files =
   browser_inspector_breadcrumbs.html
   browser_inspector_bug_650804_search.html
   browser_inspector_bug_831693_search_suggestions.html
   browser_inspector_cmd_inspect.html
   browser_inspector_dead_node_exception.html
   browser_inspector_destroyselection.html
+  browser_inspector_highlighter.html
+  browser_inspector_infobar.html
   browser_inspector_menu.html
   browser_inspector_select_last_selected.html
   browser_inspector_select_last_selected2.html
   browser_inspector_bug_848731_reset_selection_on_delete.html
   browser_inspector_bug_958456_highlight_comments.html
   head.js
 
 [browser_inspector_basic_highlighter.js]
--- a/browser/devtools/inspector/test/browser_inspector_basic_highlighter.js
+++ b/browser/devtools/inspector/test/browser_inspector_basic_highlighter.js
@@ -1,19 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Test that hovering over nodes in the markup-view shows the highlighter over
 // those nodes
-
-waitForExplicitFinish();
-
 let test = asyncTest(function*() {
   info("Loading the test document and opening the inspector");
   yield addTab("data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
   let {toolbox, inspector} = yield openInspector();
 
   info("Selecting the test node");
   yield selectNode("span", inspector);
 
--- a/browser/devtools/inspector/test/browser_inspector_breadcrumbs.js
+++ b/browser/devtools/inspector/test/browser_inspector_breadcrumbs.js
@@ -1,14 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test()
 {
-  waitForExplicitFinish();
   ignoreAllUncaughtExceptions();
 
   let nodes = [
     {nodeId: "i1111", result: "i1 i11 i111 i1111"},
     {nodeId: "i22", result: "i2 i22 i221"},
     {nodeId: "i2111", result: "i2 i21 i211 i2111"},
     {nodeId: "i21", result: "i2 i21 i211 i2111"},
     {nodeId: "i22211", result: "i2 i22 i222 i2221 i22211"},
--- a/browser/devtools/inspector/test/browser_inspector_bug_650804_search.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_650804_search.js
@@ -1,15 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test()
 {
-  waitForExplicitFinish();
-
   let inspector, searchBox, state;
   let keypressStates = [3,4,8,18,19,20,21,22];
 
   // The various states of the inspector: [key, id, isValid]
   // [
   //  what key to press,
   //  what id should be selected after the keypress,
   //  is the searched text valid selector
--- a/browser/devtools/inspector/test/browser_inspector_bug_665880.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_665880.js
@@ -1,13 +1,12 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
-  waitForExplicitFinish();
   ignoreAllUncaughtExceptions();
 
   let doc;
   let objectNode;
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
--- a/browser/devtools/inspector/test/browser_inspector_bug_672902_keyboard_shortcuts.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_672902_keyboard_shortcuts.js
@@ -2,18 +2,16 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 
 // Tests that the keybindings for highlighting different elements work as
 // intended.
 
 function test()
 {
-  waitForExplicitFinish();
-
   let doc;
   let node;
   let inspector;
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     doc = content.document;
--- a/browser/devtools/inspector/test/browser_inspector_bug_674871.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_674871.js
@@ -1,15 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test()
 {
-  waitForExplicitFinish();
-
   let doc;
   let iframeNode, iframeBodyNode;
   let inspector;
 
   let iframeSrc = "<style>" +
                   "body {" +
                   "margin:0;" +
                   "height:100%;" +
--- a/browser/devtools/inspector/test/browser_inspector_bug_699308_iframe_navigation.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_699308_iframe_navigation.js
@@ -60,18 +60,16 @@ function test() {
 
     inspector.toolbox.highlighterUtils.stopPicker().then(() => {
       iframe = null;
       gBrowser.removeCurrentTab();
       executeSoon(finish);
     });
   }
 
-  waitForExplicitFinish();
-
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad() {
     gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
     waitForFocus(startTest, content);
   }, true);
 
   content.location = "data:text/html;charset=utf-8," +
                      "<p>bug 699308 - test iframe navigation</p>" +
--- a/browser/devtools/inspector/test/browser_inspector_bug_817558_delete_node.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_817558_delete_node.js
@@ -1,14 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test()
 {
-  waitForExplicitFinish();
   //ignoreAllUncaughtExceptions();
 
   let node, iframe, inspector;
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(setupTest, content);
--- a/browser/devtools/inspector/test/browser_inspector_bug_831693_combinator_suggestions.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_831693_combinator_suggestions.js
@@ -1,15 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test()
 {
-  waitForExplicitFinish();
-
   let inspector, searchBox, state, popup;
 
   // The various states of the inspector: [key, suggestions array]
   // [
   //  what key to press,
   //  suggestions array with count [
   //    [suggestion1, count1], [suggestion2] ...
   //  ] count can be left to represent 1
--- a/browser/devtools/inspector/test/browser_inspector_bug_831693_input_suggestion.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_831693_input_suggestion.js
@@ -1,15 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test()
 {
-  waitForExplicitFinish();
-
   let inspector, searchBox, state, popup;
 
   // The various states of the inspector: [key, suggestions array]
   // [
   //  what key to press,
   //  suggestions array with count [
   //    [suggestion1, count1], [suggestion2] ...
   //  ] count can be left to represent 1
--- a/browser/devtools/inspector/test/browser_inspector_bug_831693_searchbox_panel_navigation.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_831693_searchbox_panel_navigation.js
@@ -1,14 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test()
 {
-  waitForExplicitFinish();
   requestLongerTimeout(2);
 
   let inspector, searchBox, state, panel;
   let panelOpeningStates = [0, 3, 9, 14, 17];
   let panelClosingStates = [2, 8, 13, 16];
 
   // The various states of the inspector: [key, query]
   // [
--- a/browser/devtools/inspector/test/browser_inspector_bug_840156_destroy_after_navigation.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_840156_destroy_after_navigation.js
@@ -1,18 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 let Toolbox = devtools.Toolbox;
 let TargetFactory = devtools.TargetFactory;
 
 function test() {
-  waitForExplicitFinish();
-
   const URL_1 = "data:text/plain;charset=UTF-8,abcde";
   const URL_2 = "data:text/plain;charset=UTF-8,12345";
 
   let target, toolbox;
 
   // open tab, load URL_1, and wait for load to finish
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   let target = TargetFactory.forTab(gBrowser.selectedTab);
--- a/browser/devtools/inspector/test/browser_inspector_bug_848731_reset_selection_on_delete.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_848731_reset_selection_on_delete.js
@@ -8,18 +8,16 @@
 // and therefore the markup view, css rule view, computed view, font view,
 // box model view, and breadcrumbs, reset accordingly to show the right node
 
 const TEST_PAGE = "http://mochi.test:8888/browser/browser/devtools/inspector/test/browser_inspector_bug_848731_reset_selection_on_delete.html";
 
 function test() {
   let inspector, toolbox;
 
-  waitForExplicitFinish();
-
   // Create a tab, load test HTML, wait for load and start the tests
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(function() {
       openInspector((aInspector, aToolbox) => {
         inspector = aInspector;
         toolbox = aToolbox;
--- a/browser/devtools/inspector/test/browser_inspector_bug_922125_destroy_on_navigate.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_922125_destroy_on_navigate.js
@@ -1,17 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let Toolbox = devtools.Toolbox;
 let TargetFactory = devtools.TargetFactory;
 
 function test() {
-  waitForExplicitFinish();
-
   const URL_1 = "data:text/html;charset=UTF-8,<div id='one' style='color:red;'>ONE</div>";
   const URL_2 = "data:text/html;charset=UTF-8,<div id='two' style='color:green;'>TWO</div>";
 
   let toolbox, inspector;
 
   // open tab, load URL_1, and wait for load to finish
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   let target = TargetFactory.forTab(gBrowser.selectedTab);
--- a/browser/devtools/inspector/test/browser_inspector_bug_958169_switch_to_inspector_on_pick.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_958169_switch_to_inspector_on_pick.js
@@ -3,18 +3,16 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 let doc;
 let toolbox;
 
 function test() {
-  waitForExplicitFinish();
-
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload(evt) {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     doc = content.document;
     waitForFocus(startTests, content);
   }, true);
 
   content.location = "data:text/html,<p>Switch to inspector on pick</p>";
--- a/browser/devtools/inspector/test/browser_inspector_bug_958456_highlight_comments.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_958456_highlight_comments.js
@@ -10,17 +10,16 @@
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
 
 const TEST_PAGE = "http://mochi.test:8888/browser/browser/devtools/inspector/test/browser_inspector_bug_958456_highlight_comments.html";
 let inspector, markupView, doc;
 
 function test() {
-  waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     doc = content.document;
 
     waitForFocus(function() {
       openInspector((aInspector, aToolbox) => {
         inspector = aInspector;
--- a/browser/devtools/inspector/test/browser_inspector_bug_961771_picker_stops_on_tool_select.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_961771_picker_stops_on_tool_select.js
@@ -3,18 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Test that the highlighter's picker should be stopped when a different tool is
 // selected
 
 function test() {
   let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
 
-  waitForExplicitFinish();
-
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(setupTest, content);
   }, true);
   content.location = "data:text/html,testing the highlighter goes away on tool selection";
 
   function setupTest() {
--- a/browser/devtools/inspector/test/browser_inspector_bug_962478_picker_stops_on_destroy.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_962478_picker_stops_on_destroy.js
@@ -3,18 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Test that the highlighter's picker should be stopped when the toolbox is
 // closed
 
 function test() {
   let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
 
-  waitForExplicitFinish();
-
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(runTest, content);
   }, true);
   content.location = "data:text/html,<p>testing the highlighter goes away on destroy</p>";
 
   function runTest() {
--- a/browser/devtools/inspector/test/browser_inspector_dead_node_exception.js
+++ b/browser/devtools/inspector/test/browser_inspector_dead_node_exception.js
@@ -1,16 +1,14 @@
 /* Any copyright", " is dedicated to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   let contentTab, contentDoc, inspector;
 
-  waitForExplicitFinish();
-
   // Create a tab
   contentTab = gBrowser.selectedTab = gBrowser.addTab();
 
   // Open the toolbox's inspector first
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
     inspector = toolbox.getCurrentPanel();
 
--- a/browser/devtools/inspector/test/browser_inspector_destroyselection.js
+++ b/browser/devtools/inspector/test/browser_inspector_destroyselection.js
@@ -1,15 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test()
 {
-  waitForExplicitFinish();
-
   let node, iframe, inspector;
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(setupTest, content);
   }, true);
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/inspector/test/browser_inspector_highlighter.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+    div {
+      position:absolute;
+    }
+
+    #simple-div {
+      padding: 5px;
+      border: 7px solid red;
+      margin: 9px;
+      top: 30px;
+      left: 150px;
+    }
+
+    #rotated-div {
+      padding: 5px;
+      border: 7px solid red;
+      margin: 9px;
+      transform: rotate(45deg);
+      top: 30px;
+      left: 80px;
+    }
+
+    #widthHeightZero-div {
+      top: 30px;
+      left: 10px;
+      width: 0;
+      height: 0;
+    }
+    </style>
+  </head>
+  <body>
+    <div id="simple-div">Gort! Klaatu barada nikto!</div>
+    <div id="rotated-div"></div>
+    <div id="widthHeightZero-div">Width &amp; height = 0</div>
+  </body>
+</html>
--- a/browser/devtools/inspector/test/browser_inspector_highlighter.js
+++ b/browser/devtools/inspector/test/browser_inspector_highlighter.js
@@ -3,66 +3,54 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Test that the highlighter is correctly displayed over a variety of elements
 
-waitForExplicitFinish();
+let test = asyncTest(function*() {
+  const TEST_URI = "http://example.com/browser/browser/devtools/inspector/" +
+                   "test/browser_inspector_highlighter.html";
 
-let test = asyncTest(function*() {
-  info("Adding the test tab and creating the document");
-  yield addTab("data:text/html;charset=utf-8,browser_inspector_highlighter.js");
-  createDocument(content.document);
+  info("Opening the document");
+  yield addTab(TEST_URI);
 
   info("Opening the inspector");
   let {toolbox, inspector} = yield openInspector();
 
   info("Selecting the simple, non-transformed DIV");
-  let div = getNode(".simple-div");
+  let div = getNode("#simple-div");
   yield selectNode(div, inspector, "highlight");
 
   testSimpleDivHighlighted(div);
   yield zoomTo(2);
   testZoomedSimpleDivHighlighted(div);
   yield zoomTo(1);
 
   info("Selecting the rotated DIV");
-  let rotated = getNode(".rotated-div");
+  let rotated = getNode("#rotated-div");
   let onBoxModelUpdate = waitForBoxModelUpdate();
   yield selectNode(rotated, inspector, "highlight");
   yield onBoxModelUpdate;
 
   testMouseOverRotatedHighlights(rotated);
 
+  info("Selecting the zero width height DIV");
+  let zeroWidthHeight = getNode("#widthHeightZero-div");
+  let onBoxModelUpdate = waitForBoxModelUpdate();
+  yield selectNode(zeroWidthHeight, inspector, "highlight");
+  yield onBoxModelUpdate;
+
+  testMouseOverWidthHeightZeroDiv(zeroWidthHeight);
+
   gBrowser.removeCurrentTab();
 });
 
-function createDocument(doc) {
-  info("Creating the test document");
-
-  let div = doc.createElement("div");
-  div.className = "simple-div";
-  div.setAttribute("style",
-                   "padding:5px; border:7px solid red; margin: 9px; " +
-                   "position:absolute; top:30px; left:150px;");
-  div.appendChild(doc.createTextNode("Gort! Klaatu barada nikto!"));
-  doc.body.appendChild(div);
-
-  let rotatedDiv = doc.createElement("div");
-  rotatedDiv.className = "rotated-div";
-  rotatedDiv.setAttribute("style",
-                       "padding:5px; border:7px solid red; margin: 9px; " +
-                       "transform:rotate(45deg); " +
-                       "position:absolute; top:30px; left:80px;");
-  doc.body.appendChild(rotatedDiv);
-}
-
 function testSimpleDivHighlighted(div) {
   ok(isHighlighting(), "The highlighter is shown");
   is(getHighlitNode(), div, "The highlighter's outline corresponds to the simple div");
 
   info("Checking that the simple div is correctly highlighted");
   isNodeCorrectlyHighlighted(div, "non-zoomed");
 }
 
@@ -84,8 +72,15 @@ function zoomTo(level) {
   return def.promise;
 }
 
 function testMouseOverRotatedHighlights(rotated) {
   ok(isHighlighting(), "The highlighter is shown");
   info("Checking that the rotated div is correctly highlighted");
   isNodeCorrectlyHighlighted(rotated, "rotated");
 }
+
+function testMouseOverWidthHeightZeroDiv(zeroHeightWidthDiv) {
+  ok(isHighlighting(), "The highlighter is shown");
+  info("Checking that the zero width height div is correctly highlighted");
+  isNodeCorrectlyHighlighted(zeroHeightWidthDiv, "zero width height");
+
+}
--- a/browser/devtools/inspector/test/browser_inspector_iframeTest.js
+++ b/browser/devtools/inspector/test/browser_inspector_iframeTest.js
@@ -94,18 +94,16 @@ function finishUp() {
     let target = TargetFactory.forTab(gBrowser.selectedTab);
     gDevTools.closeToolbox(target);
     gBrowser.removeCurrentTab();
     finish();
   });
 }
 
 function test() {
-  waitForExplicitFinish();
-
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     gBrowser.selectedBrowser.focus();
     createDocument();
   }, true);
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/inspector/test/browser_inspector_infobar.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+
+  <style>
+    body {
+      width: 100%;
+      height: 100%;
+    }
+
+    div {
+      position: absolute;
+      height: 100px;
+      width: 500px;
+    }
+
+    #bottom {
+      bottom: 0px;
+    }
+
+    #vertical {
+      height: 100%;
+    }
+
+    #farbottom {
+      top: 2000px;
+      background: red;
+    }
+
+    #abovetop {
+      top: -123px;
+    }";
+  </style>
+</head>
+<body>
+  <div id="abovetop"></div>
+  <div id="vertical"></div>
+  <div id="top" class="class1 class2"></div>
+  <div id="bottom"></div>
+  <div id="farbottom"></div>
+</body>
+</html>
--- a/browser/devtools/inspector/test/browser_inspector_infobar.js
+++ b/browser/devtools/inspector/test/browser_inspector_infobar.js
@@ -1,141 +1,150 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+/* 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/. */
 
-function test() {
-  waitForExplicitFinish();
-  ignoreAllUncaughtExceptions();
-
-  let doc;
-  let nodes;
-  let cursor;
-  let inspector;
+"use strict";
 
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function onload() {
-    gBrowser.selectedBrowser.removeEventListener("load", onload, true);
-    doc = content.document;
-    waitForFocus(setupInfobarTest, content);
-  }, true);
+const TEST_URI = "http://example.com/browser/browser/devtools/inspector/" +
+                 "test/browser_inspector_infobar.html";
+const DOORHANGER_ARROW_HEIGHT = 5;
 
-  let style = "body{width:100%;height: 100%} div {position: absolute;" +
-              "height: 100px;width: 500px}#bottom {bottom: 0px}#vertical {"+
-              "height: 100%}#farbottom{bottom: -200px}";
-  let html = "<style>" + style + "</style><div id=vertical></div>" +
-             "<div id=top class='class1 class2'></div><div id=bottom></div>" +
-             "<div id=farbottom></div>"
+// Test that hovering over nodes in the markup-view shows the highlighter over
+// those nodes
+let test = asyncTest(function*() {
+  info("Loading the test document and opening the inspector");
 
-  content.location = "data:text/html;charset=utf-8," + encodeURIComponent(html);
+  yield addTab(TEST_URI);
+
+  let {inspector} = yield openInspector();
 
-  function setupInfobarTest() {
-    nodes = [
-      {
-        node: doc.querySelector("#top"),
-        position: "bottom",
-        tag: "DIV",
-        id: "#top",
-        classes: ".class1.class2",
-        dims: "500 x 100"
-      },
-      {
-        node: doc.querySelector("#vertical"),
-        position: "overlap",
-        tag: "DIV",
-        id: "#vertical",
-        classes: ""
-        // No dims as they will vary between computers
-      },
-      {
-        node: doc.querySelector("#bottom"),
-        position: "top",
-        tag: "DIV",
-        id: "#bottom",
-        classes: "",
-        dims: "500 x 100"
-      },
-      {
-        node: doc.querySelector("body"),
-        position: "overlap",
-        tag: "BODY",
-        id: "",
-        classes: ""
-        // No dims as they will vary between computers
-      },
-      {
-        node: doc.querySelector("#farbottom"),
-        position: "top",
-        tag: "DIV",
-        id: "#farbottom",
-        classes: "",
-        dims: "500 x 100"
-      },
-    ];
+  let doc = content.document;
+  let testData = [
+    {
+      node: doc.querySelector("#top"),
+      position: "bottom",
+      tag: "DIV",
+      id: "#top",
+      classes: ".class1.class2",
+      dims: "500 x 100"
+    },
+    {
+      node: doc.querySelector("#vertical"),
+      position: "overlap",
+      tag: "DIV",
+      id: "#vertical",
+      classes: ""
+      // No dims as they will vary between computers
+    },
+    {
+      node: doc.querySelector("#bottom"),
+      position: "top",
+      tag: "DIV",
+      id: "#bottom",
+      classes: "",
+      dims: "500 x 100"
+    },
+    {
+      node: doc.querySelector("body"),
+      position: "bottom",
+      tag: "BODY",
+      id: "",
+      classes: ""
+      // No dims as they will vary between computers
+    },
+    {
+      node: doc.querySelector("#farbottom"),
+      position: "top",
+      tag: "DIV",
+      id: "#farbottom",
+      classes: "",
+      dims: "500 x 100"
+    },
+  ];
 
-    for (let i = 0; i < nodes.length; i++) {
-      ok(nodes[i].node, "node " + i + " found");
-    }
-
-    openInspector(runTests);
+  for (let currTest of testData) {
+    yield testPosition(currTest, inspector);
   }
 
-  function mouseOverContainerToShowHighlighter(node, cb) {
-    let container = getContainerForRawNode(inspector.markup, node);
-    EventUtils.synthesizeMouse(container.tagLine, 2, 2, {type: "mousemove"},
-      inspector.markup.doc.defaultView);
-    executeSoon(cb);
-  }
+  yield checkInfoBarAboveTop(inspector);
+  yield checkInfoBarBelowFindbar(inspector);
+
+  gBrowser.removeCurrentTab();
+});
+
+function* testPosition(currTest, inspector) {
+  let browser = gBrowser.selectedBrowser;
+  let stack = browser.parentNode;
+
+  info("Testing " + currTest.id);
 
-  function runTests(aInspector) {
-    inspector = aInspector;
-    inspector.selection.setNode(content.document.querySelector("body"));
-    inspector.once("inspector-updated", () => {
-      cursor = 0;
-      executeSoon(function() {
-        mouseOverContainerToShowHighlighter(nodes[0].node, nodeSelected);
-      });
-    });
-  }
+  yield selectNode(currTest.node, inspector, "highlight");
+
+  let container = stack.querySelector(".highlighter-nodeinfobar-positioner");
+  is(container.getAttribute("position"),
+    currTest.position, "node " + currTest.id + ": position matches.");
 
-  function nodeSelected() {
-    executeSoon(function() {
-      performTest();
-      cursor++;
-      if (cursor >= nodes.length) {
-        finishUp();
-      } else {
-        let node = nodes[cursor].node;
-        mouseOverContainerToShowHighlighter(node, nodeSelected);
-      }
-    });
+  let tagNameLabel = stack.querySelector(".highlighter-nodeinfobar-tagname");
+  is(tagNameLabel.textContent, currTest.tag,
+    "node " + currTest.id + ": tagName matches.");
+
+  if (currTest.id) {
+    let idLabel = stack.querySelector(".highlighter-nodeinfobar-id");
+    is(idLabel.textContent, currTest.id, "node " + currTest.id  + ": id matches.");
   }
 
-  function performTest() {
-    let browser = gBrowser.selectedBrowser;
-    let stack = browser.parentNode;
-
-    let container = stack.querySelector(".highlighter-nodeinfobar-positioner");
-    is(container.getAttribute("position"),
-      nodes[cursor].position, "node " + cursor + ": position matches.");
-
-    let tagNameLabel = stack.querySelector(".highlighter-nodeinfobar-tagname");
-    is(tagNameLabel.textContent, nodes[cursor].tag,
-      "node " + cursor  + ": tagName matches.");
-
-    let idLabel = stack.querySelector(".highlighter-nodeinfobar-id");
-    is(idLabel.textContent, nodes[cursor].id, "node " + cursor  + ": id matches.");
+  let classesBox = stack.querySelector(".highlighter-nodeinfobar-classes");
+  is(classesBox.textContent, currTest.classes,
+    "node " + currTest.id  + ": classes match.");
 
-    let classesBox = stack.querySelector(".highlighter-nodeinfobar-classes");
-    is(classesBox.textContent, nodes[cursor].classes,
-      "node " + cursor  + ": classes match.");
-
-    if (nodes[cursor].dims) {
-      let dimBox = stack.querySelector(".highlighter-nodeinfobar-dimensions");
-      is(dimBox.textContent, nodes[cursor].dims, "node " + cursor  + ": dims match.");
-    }
-  }
-
-  function finishUp() {
-    doc = nodes = null;
-    gBrowser.removeCurrentTab();
-    finish();
+  if (currTest.dims) {
+    let dimBox = stack.querySelector(".highlighter-nodeinfobar-dimensions");
+    is(dimBox.textContent, currTest.dims, "node " + currTest.id  + ": dims match.");
   }
 }
+
+function* checkInfoBarAboveTop(inspector) {
+  yield selectNode("#abovetop", inspector);
+
+  let positioner = getPositioner();
+  let insideContent = parseInt(positioner.style.top, 10) >= -DOORHANGER_ARROW_HEIGHT;
+
+  ok(insideContent, "Infobar is inside the content window (top = " +
+                    parseInt(positioner.style.top, 10) + ", content = '" +
+                    positioner.textContent +"')");
+}
+
+function* checkInfoBarBelowFindbar(inspector) {
+  gFindBar.open();
+
+  let body = content.document.body;
+  let farBottom = body.querySelector("#farbottom");
+  farBottom.scrollIntoView();
+
+  // Wait for scrollIntoView
+  yield waitForTick();
+
+  body.scrollTop -= 130;
+  yield selectNode(farBottom, inspector);
+
+  let positioner = getPositioner();
+  let insideContent = parseInt(positioner.style.top, 10) >= -DOORHANGER_ARROW_HEIGHT;
+
+  ok(insideContent, "Infobar does not overlap the findbar (top = " +
+                    parseInt(positioner.style.top, 10) + ", content = '" +
+                    positioner.textContent +"')");
+
+  gFindBar.close();
+}
+
+function getPositioner() {
+  let browser = gBrowser.selectedBrowser;
+  let stack = browser.parentNode;
+
+  return stack.querySelector(".highlighter-nodeinfobar-positioner");
+}
+
+function waitForTick() {
+  let deferred = promise.defer();
+  executeSoon(deferred.resolve);
+  return deferred.promise;
+}
--- a/browser/devtools/inspector/test/browser_inspector_initialization.js
+++ b/browser/devtools/inspector/test/browser_inspector_initialization.js
@@ -124,17 +124,16 @@ function inspectNodesFromContextTestWhil
 function finishInspectorTests(subject, topic, aWinIdString)
 {
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
-  waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html;charset=utf-8,browser_inspector_initialization.js";
--- a/browser/devtools/inspector/test/browser_inspector_invalidate.js
+++ b/browser/devtools/inspector/test/browser_inspector_invalidate.js
@@ -38,17 +38,16 @@ function test() {
   function finishUp() {
     inspector.toolbox.highlighter.hideBoxModel().then(() => {
       doc = div = inspector = null;
       gBrowser.removeCurrentTab();
       finish();
     });
   }
 
-  waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html;charset=utf-8,browser_inspector_invalidate.js";
--- a/browser/devtools/inspector/test/browser_inspector_menu.js
+++ b/browser/devtools/inspector/test/browser_inspector_menu.js
@@ -1,18 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/ */
 
 
 function test() {
 
   let clipboard = require("sdk/clipboard");
-
-  waitForExplicitFinish();
-
   let doc;
   let inspector;
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     doc = content.document;
     waitForFocus(setupTest, content);
--- a/browser/devtools/inspector/test/browser_inspector_navigation.js
+++ b/browser/devtools/inspector/test/browser_inspector_navigation.js
@@ -3,18 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 function test() {
   let inspector, toolbox;
 
-  waitForExplicitFinish();
-
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(function() {
       let target = TargetFactory.forTab(gBrowser.selectedTab);
       gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
         startInspectorTests(toolbox);
       }).then(null, console.error);
--- a/browser/devtools/inspector/test/browser_inspector_pseudoClass_menu.js
+++ b/browser/devtools/inspector/test/browser_inspector_pseudoClass_menu.js
@@ -7,17 +7,16 @@ function test() {
 
   let pseudos = ["hover", "active", "focus"];
 
   let doc;
   let div;
   let menu;
   let inspector;
 
-  waitForExplicitFinish();
   ignoreAllUncaughtExceptions();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
--- a/browser/devtools/inspector/test/browser_inspector_pseudoclass_lock.js
+++ b/browser/devtools/inspector/test/browser_inspector_pseudoclass_lock.js
@@ -11,18 +11,16 @@ const TEST_URL = 'data:text/html,' +
                  '</head>' +
                  '<body>' +
                  '  <div id="parent-div">' +
                  '    <div id="div-1">test div</div>' +
                  '    <div id="div-2">test div2</div>' +
                  '  </div>' +
                  '</body>';
 
-waitForExplicitFinish();
-
 function test() {
   ignoreAllUncaughtExceptions();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     waitForFocus(startTests, content);
   }, true);
 
--- a/browser/devtools/inspector/test/browser_inspector_reload.js
+++ b/browser/devtools/inspector/test/browser_inspector_reload.js
@@ -3,18 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 function test() {
   let inspector, toolbox;
 
-  waitForExplicitFinish();
-
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(function() {
       let target = TargetFactory.forTab(gBrowser.selectedTab);
       gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
         startInspectorTests(toolbox);
       }).then(null, console.error);
--- a/browser/devtools/inspector/test/browser_inspector_scrolling.js
+++ b/browser/devtools/inspector/test/browser_inspector_scrolling.js
@@ -60,17 +60,16 @@ function finishUp()
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   gDevTools.closeToolbox(target);
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
-  waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html,mouse scrolling test for inspector";
--- a/browser/devtools/inspector/test/browser_inspector_select_last_selected.js
+++ b/browser/devtools/inspector/test/browser_inspector_select_last_selected.js
@@ -4,18 +4,16 @@
  * 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/. */
 
 function test() {
   let inspector, toolbox;
   let page1 = "http://mochi.test:8888/browser/browser/devtools/inspector/test/browser_inspector_select_last_selected.html";
   let page2 = "http://mochi.test:8888/browser/browser/devtools/inspector/test/browser_inspector_select_last_selected2.html";
 
-  waitForExplicitFinish();
-
   // Create a tab, load test HTML, wait for load and start the tests
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(function() {
       openInspector((aInspector, aToolbox) => {
         inspector = aInspector;
         toolbox = aToolbox;
--- a/browser/devtools/inspector/test/browser_inspector_sidebarstate.js
+++ b/browser/devtools/inspector/test/browser_inspector_sidebarstate.js
@@ -55,17 +55,16 @@ function finishTest()
 {
   doc = inspector = null;
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
-  waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html;charset=utf-8,browser_inspector_sidebarstate.js";
--- a/browser/devtools/inspector/test/browser_inspector_tree_height.js
+++ b/browser/devtools/inspector/test/browser_inspector_tree_height.js
@@ -93,17 +93,16 @@ function treePanelTests2()
 function finishInspectorTests()
 {
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
-  waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html;charset=utf-8,browser_inspector_tree_height.js";
--- a/browser/devtools/inspector/test/head.js
+++ b/browser/devtools/inspector/test/head.js
@@ -11,16 +11,19 @@ const Cc = Components.classes;
 //   Services.prefs.clearUserPref("devtools.debugger.log");
 // });
 
 //Services.prefs.setBoolPref("devtools.dump.emit", true);
 
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 
+// All test are asynchronous
+waitForExplicitFinish();
+
 let tempScope = {};
 Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm", tempScope);
 let LayoutHelpers = tempScope.LayoutHelpers;
 
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", tempScope);
 let TargetFactory = devtools.TargetFactory;
 
 Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
@@ -86,17 +89,18 @@ function getNode(nodeOrSelector) {
 
 /**
  * Set the inspector's current selection to a node or to the first match of the
  * given css selector
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * loaded in the toolbox
  * @param {String} reason Defaults to "test" which instructs the inspector not
  * to highlight the node upon selection
- * @param {String} reason Defaults to "test" which instructs the inspector not to highlight the node upon selection
+ * @param {String} reason Defaults to "test" which instructs the inspector not
+ * to highlight the node upon selection
  * @return a promise that resolves when the inspector is updated with the new
  * node
  */
 function selectNode(nodeOrSelector, inspector, reason="test") {
   info("Selecting the node " + nodeOrSelector);
   let node = getNode(nodeOrSelector);
   let updated = inspector.once("inspector-updated");
   inspector.selection.setNode(node, reason);
@@ -502,8 +506,37 @@ function getContainerForRawNode(markupVi
   let container = markupView.getContainer(front);
   return container;
 }
 
 SimpleTest.registerCleanupFunction(function () {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   gDevTools.closeToolbox(target);
 });
+
+/**
+ * Define an async test based on a generator function
+ */
+function asyncTest(generator) {
+  return () => Task.spawn(generator).then(null, ok.bind(null, false)).then(finish);
+}
+
+/**
+ * Add a new test tab in the browser and load the given url.
+ * @param {String} url The url to be loaded in the new tab
+ * @return a promise that resolves to the tab object when the url is loaded
+ */
+function addTab(url) {
+  info("Adding a new tab with URL: '" + url + "'");
+  let def = promise.defer();
+
+  let tab = gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onload() {
+    gBrowser.selectedBrowser.removeEventListener("load", onload, true);
+    info("URL '" + url + "' loading complete");
+    waitForFocus(() => {
+      def.resolve(tab);
+    }, content);
+  }, true);
+  content.location = url;
+
+  return def.promise;
+}
--- a/browser/devtools/shared/splitview.css
+++ b/browser/devtools/shared/splitview.css
@@ -21,16 +21,17 @@ box,
 .splitview-main {
   -moz-box-flex: 0;
 }
 
 .splitview-controller {
   min-height: 3em;
   max-height: 14em;
   max-width: 400px;
+  min-width: 180px;
 }
 
 .splitview-nav {
   display: -moz-box;
   overflow-x: hidden;
   overflow-y: auto;
 }
 
--- a/browser/devtools/shared/test/browser.ini
+++ b/browser/devtools/shared/test/browser.ini
@@ -21,16 +21,17 @@ support-files =
 [browser_graphs-07.js]
 [browser_graphs-08.js]
 [browser_graphs-09.js]
 [browser_graphs-10a.js]
 [browser_graphs-10b.js]
 [browser_graphs-11.js]
 [browser_graphs-12.js]
 [browser_graphs-13.js]
+[browser_graphs-14.js]
 [browser_layoutHelpers.js]
 [browser_layoutHelpers-getBoxQuads.js]
 [browser_observableobject.js]
 [browser_outputparser.js]
 [browser_require_basic.js]
 [browser_spectrum.js]
 [browser_tableWidget_basic.js]
 [browser_tableWidget_keyboard_interaction.js]
--- a/browser/devtools/shared/test/browser_graphs-09.js
+++ b/browser/devtools/shared/test/browser_graphs-09.js
@@ -14,26 +14,28 @@ let test = Task.async(function*() {
   yield performTest();
   gBrowser.removeCurrentTab();
   finish();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
   let graph = new LineGraphWidget(doc.body, "fps");
-  yield graph.once("ready");
 
-  testGraph(graph);
+  yield testGraph(graph);
 
   graph.destroy();
   host.destroy();
 }
 
-function testGraph(graph) {
-  graph.setData(TEST_DATA);
+function* testGraph(graph) {
+  info("Should be able to set the grpah data before waiting for the ready event.");
+
+  yield graph.setDataWhenReady(TEST_DATA);
+  ok(graph.hasData(), "Data was set successfully.");
 
   is(graph._maxTooltip.querySelector("[text=info]").textContent, "max",
     "The maximum tooltip displays the correct info.");
   is(graph._avgTooltip.querySelector("[text=info]").textContent, "avg",
     "The average tooltip displays the correct info.");
   is(graph._minTooltip.querySelector("[text=info]").textContent, "min",
     "The minimum tooltip displays the correct info.");
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/test/browser_graphs-14.js
@@ -0,0 +1,92 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that graph widgets correctly emit mouse input events.
+
+const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
+let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
+let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
+let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
+let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
+
+let test = Task.async(function*() {
+  yield promiseTab("about:blank");
+  yield performTest();
+  gBrowser.removeCurrentTab();
+  finish();
+});
+
+function* performTest() {
+  let [host, win, doc] = yield createHost();
+  let graph = new LineGraphWidget(doc.body, "fps");
+
+  yield testGraph(graph);
+
+  graph.destroy();
+  host.destroy();
+}
+
+function* testGraph(graph) {
+  let mouseDownEvents = 0;
+  let mouseUpEvents = 0;
+  let scrollEvents = 0;
+  graph.on("mousedown", () => mouseDownEvents++);
+  graph.on("mouseup", () => mouseUpEvents++);
+  graph.on("scroll", () => scrollEvents++);
+
+  yield graph.setDataWhenReady(TEST_DATA);
+
+  info("Making a selection.");
+
+  dragStart(graph, 300);
+  dragStop(graph, 500);
+  is(graph.getSelection().start, 300,
+    "The current selection start value is correct (1).");
+  is(graph.getSelection().end, 500,
+    "The current selection end value is correct (1).");
+
+  is(mouseDownEvents, 1,
+    "One mousedown event should have been fired.");
+  is(mouseUpEvents, 1,
+    "One mouseup event should have been fired.");
+  is(scrollEvents, 0,
+    "No scroll event should have been fired.");
+
+  info("Zooming in by scrolling inside the selection.");
+
+  scroll(graph, -1000, 400);
+  is(graph.getSelection().start, 375,
+    "The current selection start value is correct (2).");
+  is(graph.getSelection().end, 425,
+    "The current selection end value is correct (2).");
+
+  is(mouseDownEvents, 1,
+    "No more mousedown events should have been fired.");
+  is(mouseUpEvents, 1,
+    "No more mouseup events should have been fired.");
+  is(scrollEvents, 1,
+    "One scroll event should have been fired.");
+}
+
+// EventUtils just doesn't work!
+
+function dragStart(graph, x, y = 1) {
+  x /= window.devicePixelRatio;
+  y /= window.devicePixelRatio;
+  graph._onMouseMove({ clientX: x, clientY: y });
+  graph._onMouseDown({ clientX: x, clientY: y });
+}
+
+function dragStop(graph, x, y = 1) {
+  x /= window.devicePixelRatio;
+  y /= window.devicePixelRatio;
+  graph._onMouseMove({ clientX: x, clientY: y });
+  graph._onMouseUp({ clientX: x, clientY: y });
+}
+
+function scroll(graph, wheel, x, y = 1) {
+  x /= window.devicePixelRatio;
+  y /= window.devicePixelRatio;
+  graph._onMouseMove({ clientX: x, clientY: y });
+  graph._onMouseWheel({ clientX: x, clientY: y, detail: wheel });
+}
--- a/browser/devtools/shared/widgets/Graphs.jsm
+++ b/browser/devtools/shared/widgets/Graphs.jsm
@@ -278,27 +278,40 @@ AbstractCanvasGraph.prototype = {
    */
   setData: function(data) {
     this._data = data;
     this._cachedGraphImage = this.buildGraphImage();
     this._shouldRedraw = true;
   },
 
   /**
+   * Same as `setData`, but waits for this graph to finish initializing first.
+   *
+   * @param object data
+   *        The data source. The actual format is specified by subclasses.
+   * @return promise
+   *         A promise resolved once the data is set.
+   */
+  setDataWhenReady: Task.async(function*(data) {
+    yield this.ready();
+    this.setData(data);
+  }),
+
+  /**
    * Adds regions to this graph.
    *
    * See the "Language" section in the constructor documentation
    * for details about what "regions" represent.
    *
    * @param array regions
    *        A list of { start, end } values.
    */
   setRegions: function(regions) {
     if (!this._cachedGraphImage) {
-      throw "Can't highlighted regions on a graph with no data displayed.";
+      throw "Can't highlight regions on a graph with no data displayed.";
     }
     if (this._regions) {
       throw "Regions were already highlighted on the graph.";
     }
     this._regions = regions.map(e => ({
       start: e.start * this.dataScaleX,
       end: e.end * this.dataScaleX
     }));
@@ -824,16 +837,17 @@ AbstractCanvasGraph.prototype = {
         this._selectionDragger.origin = mouseX;
         this._selectionDragger.anchor.start = this._selection.start;
         this._selectionDragger.anchor.end = this._selection.end;
         this._canvas.setAttribute("input", "dragging-selection-contents");
         break;
     }
 
     this._shouldRedraw = true;
+    this.emit("mousedown");
   },
 
   /**
    * Listener for the "mouseup" event on the graph's container.
    */
   _onMouseUp: function(e) {
     let offset = this._getContainerOffset();
     let mouseX = (e.clientX - offset.left) * this._pixelRatio;
@@ -865,16 +879,17 @@ AbstractCanvasGraph.prototype = {
 
       case "dragging-selection-contents":
         this._selectionDragger.origin = null;
         this._canvas.setAttribute("input", "hovering-selection-contents");
         break;
     }
 
     this._shouldRedraw = true;
+    this.emit("mouseup");
   },
 
   /**
    * Listener for the "wheel" event on the graph's container.
    */
   _onMouseWheel: function(e) {
     if (!this.hasSelection()) {
       return;
@@ -933,16 +948,17 @@ AbstractCanvasGraph.prototype = {
     if (thickness < GRAPH_WHEEL_MIN_SELECTION_WIDTH) {
       let midPoint = (selection.start + selection.end) / 2;
       selection.start = midPoint - GRAPH_WHEEL_MIN_SELECTION_WIDTH / 2;
       selection.end = midPoint + GRAPH_WHEEL_MIN_SELECTION_WIDTH / 2;
     }
 
     this._shouldRedraw = true;
     this.emit("selecting");
+    this.emit("scroll");
   },
 
   /**
    * Listener for the "mouseout" event on the graph's container.
    */
   _onMouseOut: function() {
     if (this.hasSelectionInProgress()) {
       this.dropSelection();
@@ -1542,16 +1558,19 @@ const gCachedStripePattern = new Map();
 /**
  * Utility functions for graph canvases.
  */
 this.CanvasGraphUtils = {
   /**
    * Merges the animation loop of two graphs.
    */
   linkAnimation: Task.async(function*(graph1, graph2) {
+    if (!graph1 || !graph2) {
+      return;
+    }
     yield graph1.ready();
     yield graph2.ready();
 
     let window = graph1._window;
     window.cancelAnimationFrame(graph1._animationId);
     window.cancelAnimationFrame(graph2._animationId);
 
     let loop = () => {
@@ -1562,16 +1581,19 @@ this.CanvasGraphUtils = {
 
     window.requestAnimationFrame(loop);
   }),
 
   /**
    * Makes sure selections in one graph are reflected in another.
    */
   linkSelection: function(graph1, graph2) {
+    if (!graph1 || !graph2) {
+      return;
+    }
     graph1.on("selecting", () => {
       graph2.setSelection(graph1.getSelection());
     });
     graph2.on("selecting", () => {
       graph1.setSelection(graph2.getSelection());
     });
     graph1.on("deselecting", () => {
       graph2.dropSelection();
--- a/browser/devtools/styleeditor/StyleEditorUI.jsm
+++ b/browser/devtools/styleeditor/StyleEditorUI.jsm
@@ -29,16 +29,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const { PrefObserver, PREF_ORIG_SOURCES } = require("devtools/styleeditor/utils");
 const csscoverage = require("devtools/server/actors/csscoverage");
 const console = require("resource://gre/modules/devtools/Console.jsm").console;
 
 const LOAD_ERROR = "error-load";
 const STYLE_EDITOR_TEMPLATE = "stylesheet";
 const PREF_MEDIA_SIDEBAR = "devtools.styleeditor.showMediaSidebar";
+const PREF_SIDEBAR_WIDTH = "devtools.styleeditor.mediaSidebarWidth";
+const PREF_NAV_WIDTH = "devtools.styleeditor.navSidebarWidth";
 
 /**
  * StyleEditorUI is controls and builds the UI of the Style Editor, including
  * maintaining a list of editors for each stylesheet on a debuggee.
  *
  * Emits events:
  *   'editor-added': A new editor was added to the UI
  *   'editor-selected': An editor was selected
@@ -59,17 +61,18 @@ function StyleEditorUI(debuggee, target,
   this._panelDoc = panelDoc;
   this._window = this._panelDoc.defaultView;
   this._root = this._panelDoc.getElementById("style-editor-chrome");
 
   this.editors = [];
   this.selectedEditor = null;
   this.savedLocations = {};
 
-  this._updateOptionsMenu = this._updateOptionsMenu.bind(this);
+  this._onOptionsPopupShowing = this._onOptionsPopupShowing.bind(this);
+  this._onOptionsPopupHiding = this._onOptionsPopupHiding.bind(this);
   this._onStyleSheetCreated = this._onStyleSheetCreated.bind(this);
   this._onNewDocument = this._onNewDocument.bind(this);
   this._onMediaPrefChanged = this._onMediaPrefChanged.bind(this);
   this._updateMediaList = this._updateMediaList.bind(this);
   this._clear = this._clear.bind(this);
   this._onError = this._onError.bind(this);
 
   this._prefObserver = new PrefObserver("devtools.styleeditor.");
@@ -137,39 +140,54 @@ StyleEditorUI.prototype = {
     wire(this._view.rootElement, ".style-editor-newButton", () =>{
       this._debuggee.addStyleSheet(null).then(this._onStyleSheetCreated);
     });
 
     wire(this._view.rootElement, ".style-editor-importButton", ()=> {
       this._importFromFile(this._mockImportFile || null, this._window);
     });
 
+    this._optionsButton = this._panelDoc.getElementById("style-editor-options");
     this._optionsMenu = this._panelDoc.getElementById("style-editor-options-popup");
     this._optionsMenu.addEventListener("popupshowing",
-                                       this._updateOptionsMenu);
+                                       this._onOptionsPopupShowing);
+    this._optionsMenu.addEventListener("popuphiding",
+                                       this._onOptionsPopupHiding);
 
     this._sourcesItem = this._panelDoc.getElementById("options-origsources");
     this._sourcesItem.addEventListener("command",
                                        this._toggleOrigSources);
     this._mediaItem = this._panelDoc.getElementById("options-show-media");
     this._mediaItem.addEventListener("command",
                                      this._toggleMediaSidebar);
+
+    let nav = this._panelDoc.querySelector(".splitview-controller");
+    nav.setAttribute("width", Services.prefs.getIntPref(PREF_NAV_WIDTH));
   },
 
   /**
+   * Listener handling the 'gear menu' popup showing event.
    * Update options menu items to reflect current preference settings.
    */
-  _updateOptionsMenu: function() {
+  _onOptionsPopupShowing: function() {
+    this._optionsButton.setAttribute("open", "true");
     this._sourcesItem.setAttribute("checked",
       Services.prefs.getBoolPref(PREF_ORIG_SOURCES));
     this._mediaItem.setAttribute("checked",
       Services.prefs.getBoolPref(PREF_MEDIA_SIDEBAR));
   },
 
   /**
+   * Listener handling the 'gear menu' popup hiding event.
+   */
+  _onOptionsPopupHiding: function() {
+    this._optionsButton.removeAttribute("open");
+  },
+
+  /**
    * Refresh editors to reflect the stylesheets in the document.
    *
    * @param {string} event
    *        Event name
    * @param {StyleSheet} styleSheet
    *        StyleSheet object for new sheet
    */
   _onNewDocument: function() {
@@ -449,16 +467,32 @@ StyleEditorUI.prototype = {
 
         summary.addEventListener("focus", function onSummaryFocus(event) {
           if (event.target == summary) {
             // autofocus the stylesheet name
             summary.querySelector(".stylesheet-name").focus();
           }
         }, false);
 
+        let sidebar = details.querySelector(".stylesheet-sidebar");
+        sidebar.setAttribute("width",
+            Services.prefs.getIntPref(PREF_SIDEBAR_WIDTH));
+
+        let splitter = details.querySelector(".devtools-side-splitter");
+        splitter.addEventListener("mousemove", () => {
+          let sidebarWidth = sidebar.getAttribute("width");
+          Services.prefs.setIntPref(PREF_SIDEBAR_WIDTH, sidebarWidth);
+
+          // update all @media sidebars for consistency
+          let sidebars = [...this._panelDoc.querySelectorAll(".stylesheet-sidebar")];
+          for (let mediaSidebar of sidebars) {
+            mediaSidebar.setAttribute("width", sidebarWidth);
+          }
+        });
+
         // autofocus if it's a new user-created stylesheet
         if (editor.isNew) {
           this._selectEditor(editor);
         }
 
         if (this._styleSheetToSelect
             && this._styleSheetToSelect.stylesheet == editor.styleSheet.href) {
           this.switchToSelectedSheet();
@@ -783,16 +817,22 @@ StyleEditorUI.prototype = {
   _jumpToLocation: function(location) {
     let source = location.styleSheet || location.source;
     this.selectStyleSheet(source, location.line - 1, location.column - 1);
   },
 
   destroy: function() {
     this._clearStyleSheetEditors();
 
+    let sidebar = this._panelDoc.querySelector(".splitview-controller");
+    let sidebarWidth = sidebar.getAttribute("width");
+    Services.prefs.setIntPref(PREF_NAV_WIDTH, sidebarWidth);
+
     this._optionsMenu.removeEventListener("popupshowing",
-                                          this._updateOptionsMenu);
+                                          this._onOptionsPopupShowing);
+    this._optionsMenu.removeEventListener("popuphiding",
+                                          this._onOptionsPopupHiding);
 
     this._prefObserver.off(PREF_ORIG_SOURCES, this._onNewDocument);
     this._prefObserver.off(PREF_MEDIA_SIDEBAR, this._onMediaPrefChanged);
     this._prefObserver.destroy();
   }
 }
--- a/browser/devtools/styleeditor/styleeditor.xul
+++ b/browser/devtools/styleeditor/styleeditor.xul
@@ -97,17 +97,17 @@
                           label="&newButton.label;"/>
               <xul:toolbarbutton class="style-editor-importButton devtools-toolbarbutton"
                           accesskey="&importButton.accesskey;"
                           tooltiptext="&importButton.tooltip;"
                           label="&importButton.label;"/>
             </xul:hbox>
             <xul:spacer/>
             <xul:toolbarbutton id="style-editor-options"
-                        class="devtools-option-toolbarbutton"
+                        class="devtools-toolbarbutton devtools-option-toolbarbutton"
                         tooltiptext="&optionsButton.tooltip;"
                         popup="style-editor-options-popup"/>
           </xul:toolbar>
         </xul:box>
         <xul:box id="splitview-resizer-target" class="theme-sidebar splitview-nav-container"
                 persist="height">
           <ol class="splitview-nav" tabindex="0"></ol>
           <div class="splitview-nav placeholder empty">
@@ -143,16 +143,17 @@
 
         <xul:box id="splitview-tpl-details-stylesheet" class="splitview-details">
           <xul:resizer class="splitview-portrait-resizer"
                       dir="bottom"
                       element="splitview-resizer-target"/>
           <xul:hbox class="stylesheet-details-container">
             <xul:box class="stylesheet-editor-input textbox"
                      data-placeholder="&editorTextbox.placeholder;"/>
+            <xul:splitter class="devtools-side-splitter"/>
             <xul:vbox class="stylesheet-sidebar theme-sidebar" hidden="true">
               <xul:toolbar class="devtools-toolbar">
                 &mediaRules.label;
               </xul:toolbar>
               <xul:vbox class="stylesheet-media-container" flex="1">
                 <div class="stylesheet-media-list" />
               </xul:vbox>
             </xul:vbox>
--- a/browser/devtools/webaudioeditor/test/browser.ini
+++ b/browser/devtools/webaudioeditor/test/browser.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
 subsuite = devtools
 support-files =
   doc_simple-context.html
   doc_complex-context.html
   doc_simple-node-creation.html
   doc_buffer-and-array.html
+  doc_media-node-creation.html
   440hz_sine.ogg
   head.js
 
 [browser_audionode-actor-get-set-param.js]
 [browser_audionode-actor-get-type.js]
 [browser_audionode-actor-get-params-01.js]
 [browser_audionode-actor-get-params-02.js]
 [browser_audionode-actor-get-param-flags.js]
@@ -27,12 +28,13 @@ support-files =
 [browser_wa_graph-render-02.js]
 [browser_wa_graph-markers.js]
 [browser_wa_graph-selected.js]
 
 [browser_wa_inspector.js]
 [browser_wa_inspector-toggle.js]
 
 [browser_wa_properties-view.js]
+[browser_wa_properties-view-media-nodes.js]
 # [browser_wa_properties-view-edit.js]
 # Disabled for too many intermittents bug 1010423
 [browser_wa_properties-view-params.js]
 [browser_wa_properties-view-params-objects.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webaudioeditor/test/browser_wa_properties-view-media-nodes.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that params view correctly displays all properties for nodes
+ * correctly, with default values and correct types.
+ */
+
+let MEDIA_PERMISSION = "media.navigator.permission.disabled";
+
+function spawnTest() {
+  let [target, debuggee, panel] = yield initWebAudioEditor(MEDIA_NODES_URL);
+  let { panelWin } = panel;
+  let { gFront, $, $$, EVENTS, WebAudioInspectorView } = panelWin;
+  let gVars = WebAudioInspectorView._propsView;
+
+  // Auto enable getUserMedia
+  let mediaPermissionPref = Services.prefs.getBoolPref(MEDIA_PERMISSION);
+  Services.prefs.setBoolPref(MEDIA_PERMISSION, true);
+
+  reload(target);
+
+  let [actors] = yield Promise.all([
+    getN(gFront, "create-node", 4),
+    waitForGraphRendered(panelWin, 4, 0)
+  ]);
+
+  let nodeIds = actors.map(actor => actor.actorID);
+  let types = [
+    "AudioDestinationNode", "MediaElementAudioSourceNode",
+    "MediaStreamAudioSourceNode", "MediaStreamAudioDestinationNode"
+  ];
+
+  for (let i = 0; i < types.length; i++) {
+    click(panelWin, findGraphNode(panelWin, nodeIds[i]));
+    yield once(panelWin, EVENTS.UI_INSPECTOR_NODE_SET);
+    checkVariableView(gVars, 0, NODE_DEFAULT_VALUES[types[i]], types[i]);
+  }
+
+  // Reset permissions on getUserMedia
+  Services.prefs.setBoolPref(MEDIA_PERMISSION, mediaPermissionPref);
+
+  yield teardown(panel);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webaudioeditor/test/doc_media-node-creation.html
@@ -0,0 +1,29 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>Web Audio Editor test page</title>
+  </head>
+
+  <body>
+
+    <script type="text/javascript;version=1.8">
+      "use strict";
+
+      let ctx = new AudioContext();
+      let audio = new Audio();
+      let meNode, msNode, mdNode;
+      navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia;
+
+      navigator.getUserMedia({ audio: true }, stream => {
+        meNode = ctx.createMediaElementSource(audio);
+        msNode = ctx.createMediaStreamSource(stream);
+        mdNode = ctx.createMediaStreamDestination();
+      }, () => {});
+    </script>
+  </body>
+
+</html>
--- a/browser/devtools/webaudioeditor/test/head.js
+++ b/browser/devtools/webaudioeditor/test/head.js
@@ -19,16 +19,17 @@ let { DebuggerServer } = Cu.import("reso
 
 let { WebAudioFront } = devtools.require("devtools/server/actors/webaudio");
 let TargetFactory = devtools.TargetFactory;
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/webaudioeditor/test/";
 const SIMPLE_CONTEXT_URL = EXAMPLE_URL + "doc_simple-context.html";
 const COMPLEX_CONTEXT_URL = EXAMPLE_URL + "doc_complex-context.html";
 const SIMPLE_NODES_URL = EXAMPLE_URL + "doc_simple-node-creation.html";
+const MEDIA_NODES_URL = EXAMPLE_URL + "doc_media-node-creation.html";
 const BUFFER_AND_ARRAY_URL = EXAMPLE_URL + "doc_buffer-and-array.html";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 let gToolEnabled = Services.prefs.getBoolPref("devtools.webaudioeditor.enabled");
 
 registerCleanupFunction(() => {
@@ -211,16 +212,26 @@ function waitForGraphRendered (front, no
   });
   return deferred.promise;
 }
 
 function checkVariableView (view, index, hash, description = "") {
   info("Checking Variable View");
   let scope = view.getScopeAtIndex(index);
   let variables = Object.keys(hash);
+
+  // If node shouldn't display any properties, ensure that the 'empty' message is
+  // visible
+  if (!variables.length) {
+    ok(isVisible(scope.window.$("#properties-tabpanel-content-empty")),
+      description + " should show the empty properties tab.");
+    return;
+  }
+
+  // Otherwise, iterate over expected properties
   variables.forEach(variable => {
     let aVar = scope.get(variable);
     is(aVar.target.querySelector(".name").getAttribute("value"), variable,
       "Correct property name for " + variable);
     let value = aVar.target.querySelector(".value").getAttribute("value");
 
     // Cast value with JSON.parse if possible;
     // will fail when displaying Object types like "ArrayBuffer"
@@ -362,16 +373,21 @@ function countGraphObjects (win) {
 }
 
 /**
  * List of audio node properties to test against expectations of the AudioNode actor
  */
 
 const NODE_DEFAULT_VALUES = {
   "AudioDestinationNode": {},
+  "MediaElementAudioSourceNode": {},
+  "MediaStreamAudioSourceNode": {},
+  "MediaStreamAudioDestinationNode": {
+    "stream": "MediaStream"
+  },
   "AudioBufferSourceNode": {
     "playbackRate": 1,
     "loop": false,
     "loopStart": 0,
     "loopEnd": 0,
     "buffer": null
   },
   "ScriptProcessorNode": {
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -224,17 +224,23 @@ this.ContentSearch = {
     let deferred = Promise.defer();
     let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
               createInstance(Ci.nsIXMLHttpRequest);
     xhr.open("GET", uri, true);
     xhr.responseType = "arraybuffer";
     xhr.onloadend = () => {
       deferred.resolve(xhr.response);
     };
-    xhr.send();
+    try {
+      // This throws if the URI is erroneously encoded.
+      xhr.send();
+    }
+    catch (err) {
+      return Promise.resolve(null);
+    }
     return deferred.promise;
   },
 
   _initService: function () {
     if (!this._initServicePromise) {
       let deferred = Promise.defer();
       this._initServicePromise = deferred.promise;
       Services.search.init(() => deferred.resolve());
--- a/browser/modules/test/browser.ini
+++ b/browser/modules/test/browser.ini
@@ -1,17 +1,19 @@
 [DEFAULT]
 support-files =
   head.js
-  contentSearch.js
   image.png
   uitour.*
 
 [browser_BrowserUITelemetry_buckets.js]
 [browser_ContentSearch.js]
+support-files =
+  contentSearch.js
+  contentSearchBadImage.xml
 [browser_NetworkPrioritizer.js]
 skip-if = e10s # Bug 666804 - Support NetworkPrioritizer in e10s
 [browser_SignInToWebsite.js]
 skip-if = e10s # Bug 941426 - SignIntoWebsite.jsm not e10s friendly
 [browser_UITour.js]
 skip-if = os == "linux" || e10s # Intermittent failures, bug 951965
 [browser_UITour2.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
--- a/browser/modules/test/browser_ContentSearch.js
+++ b/browser/modules/test/browser_ContentSearch.js
@@ -141,16 +141,41 @@ add_task(function* search() {
       }
     }
   };
   gBrowser.addProgressListener(listener);
   info("Waiting for search URL to load: " + submissionURL);
   yield deferred.promise;
 });
 
+add_task(function* badImage() {
+  yield addTab();
+  // If the bad image URI caused an exception to be thrown within ContentSearch,
+  // then we'll hang waiting for the CurrentState responses triggered by the new
+  // engine.  That's what we're testing, and obviously it shouldn't happen.
+  let vals = yield waitForNewEngine("contentSearchBadImage.xml", 1);
+  let engine = vals[0];
+  let finalCurrentStateMsg = vals[vals.length - 1];
+  let expectedCurrentState = yield currentStateObj();
+  let expectedEngine =
+    expectedCurrentState.engines.find(e => e.name == engine.name);
+  ok(!!expectedEngine, "Sanity check: engine should be in expected state");
+  ok(expectedEngine.iconBuffer === null,
+     "Sanity check: icon array buffer of engine in expected state " +
+     "should be null: " + expectedEngine.iconBuffer);
+  checkMsg(finalCurrentStateMsg, {
+    type: "CurrentState",
+    data: expectedCurrentState,
+  });
+  // Removing the engine triggers a final CurrentState message.  Wait for it so
+  // it doesn't trip up subsequent tests.
+  Services.search.removeEngine(engine);
+  yield waitForTestMsg("CurrentState");
+});
+
 function checkMsg(actualMsg, expectedMsgData) {
   SimpleTest.isDeeply(actualMsg.data, expectedMsgData, "Checking message");
 }
 
 function waitForMsg(name, type) {
   let deferred = Promise.defer();
   info("Waiting for " + name + " message " + type + "...");
   gMsgMan.addMessageListener(name, function onMsg(msg) {
@@ -162,16 +187,45 @@ function waitForMsg(name, type) {
   });
   return deferred.promise;
 }
 
 function waitForTestMsg(type) {
   return waitForMsg(TEST_MSG, type);
 }
 
+function waitForNewEngine(basename, numImages) {
+  info("Waiting for engine to be added: " + basename);
+
+  // Wait for the search events triggered by adding the new engine.
+  // engine-added engine-loaded
+  let expectedSearchEvents = ["CurrentState", "CurrentState"];
+  // engine-changed for each of the images
+  for (let i = 0; i < numImages; i++) {
+    expectedSearchEvents.push("CurrentState");
+  }
+  let eventPromises = expectedSearchEvents.map(e => waitForTestMsg(e));
+
+  // Wait for addEngine().
+  let addDeferred = Promise.defer();
+  let url = getRootDirectory(gTestPath) + basename;
+  Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "", false, {
+    onSuccess: function (engine) {
+      info("Search engine added: " + basename);
+      addDeferred.resolve(engine);
+    },
+    onError: function (errCode) {
+      ok(false, "addEngine failed with error code " + errCode);
+      addDeferred.reject();
+    },
+  });
+
+  return Promise.all([addDeferred.promise].concat(eventPromises));
+}
+
 function addTab() {
   let deferred = Promise.defer();
   let tab = gBrowser.addTab();
   gBrowser.selectedTab = tab;
   tab.linkedBrowser.addEventListener("load", function load() {
     tab.removeEventListener("load", load, true);
     let url = getRootDirectory(gTestPath) + TEST_CONTENT_SCRIPT_BASENAME;
     gMsgMan = tab.linkedBrowser.messageManager;
@@ -225,11 +279,16 @@ function arrayBufferFromDataURI(uri) {
   let deferred = Promise.defer();
   let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
             createInstance(Ci.nsIXMLHttpRequest);
   xhr.open("GET", uri, true);
   xhr.responseType = "arraybuffer";
   xhr.onloadend = () => {
     deferred.resolve(xhr.response);
   };
-  xhr.send();
+  try {
+    xhr.send();
+  }
+  catch (err) {
+    return Promise.resolve(null);
+  }
   return deferred.promise;
 }
new file mode 100644
--- /dev/null
+++ b/browser/modules/test/contentSearchBadImage.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>browser_ContentSearch contentSearchBadImage.xml</ShortName>
+<Url type="text/html" method="GET" template="http://browser-ContentSearch.com/contentSearchBadImage" rel="searchform"/>
+<Image width="16" height="16">data:image/x-icon;base64,notbase64</Image>
+</SearchPlugin>
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -46,16 +46,28 @@
   background-color: -moz-Dialog;
 }
 
 #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar) {
   padding-top: 1px;
   padding-bottom: 1px;
 }
 
+#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar):not(#addon-bar) {
+  overflow: -moz-hidden-unscrollable;
+  max-height: 4em;
+  transition: min-height 170ms ease-out, max-height 170ms ease-out;
+}
+
+#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar):not(#addon-bar)[collapsed=true] {
+  min-height: 0.1px;
+  max-height: 0;
+  transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
+}
+
 #TabsToolbar:not([collapsed="true"]) + #nav-bar {
   border-top: 1px solid hsla(0,0%,0%,.3) !important;
   background-clip: padding-box;
   margin-top: -1px; /* Move up into the TabsToolbar for the inner highlight at the top of the nav-bar */
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -104,16 +104,28 @@ toolbarseparator {
   min-height: 22px;
 }
 
 #navigator-toolbox > toolbar:not(#TabsToolbar):not(#nav-bar):not(:-moz-lwtheme) {
   -moz-appearance: none;
   background: url(chrome://browser/skin/Toolbar-background-noise.png) hsl(0,0%,83%);
 }
 
+#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar):not(#addon-bar) {
+  overflow: -moz-hidden-unscrollable;
+  max-height: 4em;
+  transition: min-height 170ms ease-out, max-height 170ms ease-out;
+}
+
+#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar):not(#addon-bar)[collapsed=true] {
+  min-height: 0.1px;
+  max-height: 0;
+  transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
+}
+
 #nav-bar {
   -moz-appearance: none;
   background: url(chrome://browser/skin/Toolbar-background-noise.png),
               linear-gradient(hsl(0,0%,93%), hsl(0,0%,83%));
   background-clip: border-box;
   background-origin: border-box !important;
 
   /* Move the noise texture out of the top 1px strip because that overlaps
@@ -144,17 +156,17 @@ toolbarseparator {
   position: relative;
   z-index: 1;
 }
 
 #nav-bar-customization-target {
   padding: 4px;
 }
 
-#PersonalToolbar {
+#PersonalToolbar:not([collapsed=true]) {
   padding: 0 4px 4px;
   /* 4px padding ^  plus 19px personal-bookmarks (see below) */
   min-height: 23px;
 }
 
 #navigator-toolbox > toolbar:not(#TabsToolbar):-moz-lwtheme {
   background-color: @toolbarColorLWT@;
   background-image: url(chrome://browser/skin/Toolbar-background-noise.png);
--- a/browser/themes/shared/devtools/styleeditor.css
+++ b/browser/themes/shared/devtools/styleeditor.css
@@ -60,18 +60,18 @@
   font-style: italic;
 }
 
 .splitview-nav.empty > p {
   padding: 0 10px;
 }
 
 .stylesheet-sidebar {
-  width: 237px;
-  -moz-border-start: 1px solid;
+  max-width: 400px;
+  min-width: 100px;
 }
 
 .theme-light .stylesheet-sidebar {
   border-color: #aaa; /* Splitters */
 }
 
 .theme-dark .stylesheet-sidebar {
   border-color: #000;  /* Splitters */
@@ -120,21 +120,16 @@
     background-image: url(itemToggle@2x.png);
   }
 }
 
 .disabled > .stylesheet-enabled {
   background-position: -24px 8px;
 }
 
-#style-editor-options {
-  width: 20px;
-  overflow: hidden;
-}
-
 /* Invert all toggle icons but the one in the active row for light theme */
 .theme-light .splitview-nav > li:not(.splitview-active) .stylesheet-enabled {
   filter: url(filters.svg#invert);
 }
 
 .splitview-nav > li > .stylesheet-enabled:focus,
 .splitview-nav > li:hover > .stylesheet-enabled {
   outline: 0;
--- a/browser/themes/shared/devtools/toolbars.inc.css
+++ b/browser/themes/shared/devtools/toolbars.inc.css
@@ -20,29 +20,43 @@
   line-height: 24px;
   box-sizing: border-box;
 }
 
 .devtools-toolbar {
   padding: 0 3px;
 }
 
+.devtools-toolbar checkbox {
+  margin: 0 2px;
+  padding: 0;
+}
+.devtools-toolbar checkbox .checkbox-check {
+  margin: 0;
+  padding: 0;
+}
+.devtools-toolbar checkbox .checkbox-label-box .checkbox-label {
+  margin: 0 6px !important; /* overrides .checkbox-label from checkbox.css */
+  padding: 0;
+}
+
 /* Toolbar buttons */
 .devtools-menulist,
 .devtools-toolbarbutton {
   -moz-appearance: none;
   -moz-box-align: center;
   background: transparent;
   min-width: 78px;
   min-height: 18px;
   padding: 1px;
   text-shadow: none;
   border: none;
   border-radius: 0;
   margin: 2px 3px;
+  color: inherit;
 }
 
 .devtools-menulist:-moz-focusring,
 .devtools-toolbarbutton:-moz-focusring {
   outline: 1px dotted hsla(210,30%,85%,0.7);
   outline-offset: -4px;
 }
 
@@ -67,32 +81,33 @@
 .devtools-toolbar .devtools-toolbarbutton {
   border-width: 0;
 }
 
 .devtools-toolbarbutton > .toolbarbutton-icon {
   margin: 0;
 }
 
-.devtools-toolbarbutton > .toolbarbutton-menubutton-button {
-  -moz-box-orient: horizontal;
-  padding: 0;
-}
-
 .devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-button {
   -moz-appearance: none;
   color: inherit;
   border-width: 0;
+  -moz-box-orient: horizontal;
+  padding: 0;
 }
 
 .devtools-toolbarbutton[type=menu-button] {
   padding: 0 1px;
   -moz-box-align: stretch;
 }
 
+.devtools-toolbarbutton > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+  -moz-margin-end: 4px;
+}
+
 .devtools-menulist > .menulist-dropmarker {
   -moz-appearance: none;
   display: -moz-box;
   list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
   -moz-box-align: center;
   min-width: 16px;
 }
 
--- a/browser/themes/shared/devtools/widgets.inc.css
+++ b/browser/themes/shared/devtools/widgets.inc.css
@@ -198,16 +198,22 @@
   min-width: 65px;
   margin: 0;
   padding: 0 8px 0 20px;
   border: none;
   outline: none;
   color: hsl(210,30%,85%);
 }
 
+.breadcrumbs-widget-item > .button-box {
+  border: none;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
 .breadcrumbs-widget-item:not([checked]) {
   background: -moz-element(#breadcrumb-separator-normal) no-repeat center left;
 }
 
 .breadcrumbs-widget-item[checked] + .breadcrumbs-widget-item {
   background: -moz-element(#breadcrumb-separator-after) no-repeat 0 0;
 }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -73,16 +73,28 @@
   -moz-appearance: none;
   border-style: none;
 }
 
 #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(:-moz-lwtheme) {
   background-color: -moz-Dialog;
 }
 
+#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar):not(#addon-bar) {
+  overflow: -moz-hidden-unscrollable;
+  max-height: 4em;
+  transition: min-height 170ms ease-out, max-height 170ms ease-out;
+}
+
+#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar):not(#addon-bar)[collapsed=true] {
+  min-height: 0.1px;
+  max-height: 0;
+  transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
+}
+
 %ifdef WINDOWS_AERO
 @media not all and (-moz-windows-compositor),
        not all and (-moz-windows-default-theme) {
 %endif
   #main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar:not(:-moz-lwtheme),
   #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) {
     color: CaptionText;
   }
--- a/dom/base/DOMRequestHelper.jsm
+++ b/dom/base/DOMRequestHelper.jsm
@@ -78,28 +78,33 @@ DOMRequestIpcHelper.prototype = {
 
     if (!Array.isArray(aMessages)) {
       aMessages = [aMessages];
     }
 
     aMessages.forEach((aMsg) => {
       let name = aMsg.name || aMsg;
       // If the listener is already set and it is of the same type we just
-      // bail out. If it is not of the same type, we throw an exception.
+      // increase the count and bail out. If it is not of the same type,
+      // we throw an exception.
       if (this._listeners[name] != undefined) {
-        if (!!aMsg.weakRef == this._listeners[name]) {
+        if (!!aMsg.weakRef == this._listeners[name].weakRef) {
+          this._listeners[name].count++;
           return;
         } else {
           throw Cr.NS_ERROR_FAILURE;
         }
       }
 
       aMsg.weakRef ? cpmm.addWeakMessageListener(name, this)
                    : cpmm.addMessageListener(name, this);
-      this._listeners[name] = !!aMsg.weakRef;
+      this._listeners[name] = {
+        weakRef: !!aMsg.weakRef,
+        count: 1
+      };
     });
   },
 
   /**
    * 'aMessages' is expected to be a string or an array of strings containing
    * the message names of the listeners to be removed.
    */
   removeMessageListeners: function(aMessages) {
@@ -111,19 +116,24 @@ DOMRequestIpcHelper.prototype = {
       aMessages = [aMessages];
     }
 
     aMessages.forEach((aName) => {
       if (this._listeners[aName] == undefined) {
         return;
       }
 
-      this._listeners[aName] ? cpmm.removeWeakMessageListener(aName, this)
-                             : cpmm.removeMessageListener(aName, this);
-      delete this._listeners[aName];
+      // Only remove the listener really when we don't have anybody that could
+      // be waiting on a message.
+      if (!--this._listeners[aName].count) {
+        this._listeners[aName].weakRef ?
+            cpmm.removeWeakMessageListener(aName, this)
+          : cpmm.removeMessageListener(aName, this);
+        delete this._listeners[aName];
+      }
     });
   },
 
   /**
    * Initialize the helper adding the corresponding listeners to the messages
    * provided as the second parameter.
    *
    * 'aMessages' is expected to be an array of either:
--- a/dom/base/test/test_domrequesthelper.xul
+++ b/dom/base/test/test_domrequesthelper.xul
@@ -61,30 +61,32 @@
       is(dummy._messages, undefined, "Messages is undefined");
       is(dummy._window, undefined, "Window is undefined");
     }
 
     /**
      * Message listeners.
      */
     function checkMessageListeners(aExpectedListeners, aCount) {
-      ok(true, "Checking message listeners\n" + "Expected listeners " +
-         JSON.stringify(aExpectedListeners) + " \nExpected count " + aCount);
+      info("Checking message listeners\n" + "Expected listeners " +
+           JSON.stringify(aExpectedListeners) + " \nExpected count " + aCount);
       let count = 0;
       Object.keys(dummy._listeners).forEach(function(name) {
         count++;
-        is(aExpectedListeners[name], dummy._listeners[name],
-           "Message found " + name + " - Same listeners");
+        is(aExpectedListeners[name].weakRef, dummy._listeners[name].weakRef,
+           "Message found " + name + " - Same weakRef");
+        is(aExpectedListeners[name].count, dummy._listeners[name].count,
+           "Message found " + name + " - Same count");
       });
       is(aCount, count, "Correct number of listeners");
     }
 
     function addMessageListenersTest(aMessages, aExpectedListeners, aCount) {
       dummy.addMessageListeners(aMessages);
-      ok(true, JSON.stringify(dummy._listeners));
+      info(JSON.stringify(dummy._listeners));
       checkMessageListeners(aExpectedListeners, aCount);
     }
 
     function removeMessageListenersTest(aMessages, aExpectedListeners, aCount) {
       dummy.removeMessageListeners(aMessages);
       checkMessageListeners(aExpectedListeners, aCount);
     }
 
@@ -160,248 +162,271 @@
       document.documentElement.appendChild(frame);
     }
 
     /**
      * Test steps.
      */
     var tests = [
       function() {
-        ok(true, "== InitDOMRequestHelper no messages");
+        info("== InitDOMRequestHelper no messages");
         initDOMRequestHelperTest(null);
         next();
       },
       function() {
-        ok(true, "== DestroyDOMRequestHelper");
+        info("== DestroyDOMRequestHelper");
         destroyDOMRequestHelperTest();
         next();
       },
       function() {
-        ok(true, "== InitDOMRequestHelper empty array");
+        info("== InitDOMRequestHelper empty array");
         initDOMRequestHelperTest([]);
         checkMessageListeners({}, 0);
         next();
       },
       function() {
-        ok(true, "== DestroyDOMRequestHelper");
+        info("== DestroyDOMRequestHelper");
         destroyDOMRequestHelperTest();
         next();
       },
       function() {
-        ok(true, "== InitDOMRequestHelper with strings array");
+        info("== InitDOMRequestHelper with strings array");
         initDOMRequestHelperTest(["name1", "nameN"]);
-        checkMessageListeners({"name1": false, "nameN": false}, 2);
+        checkMessageListeners({"name1": {weakRef: false, count: 1},
+                               "nameN": {weakRef: false, count: 1}}, 2);
         next();
       },
       function() {
-        ok(true, "== DestroyDOMRequestHelper");
+        info("== DestroyDOMRequestHelper");
         destroyDOMRequestHelperTest();
         next();
       },
       function() {
-        ok(true, "== InitDOMRequestHelper with objects array");
+        info("== InitDOMRequestHelper with objects array");
         initDOMRequestHelperTest([{
           name: "name1",
           weakRef: false
         }, {
           name: "nameN",
           weakRef: true
         }]);
-        checkMessageListeners({"name1": false, "nameN": true}, 2);
-        next();
-      },
-      function() {
-        ok(true, "== AddMessageListeners empty array");
-        addMessageListenersTest([], {"name1": false, "nameN": true}, 2);
+        checkMessageListeners({
+          "name1": {weakRef: false, count: 1},
+          "nameN": {weakRef: true,  count: 1}
+        }, 2);
         next();
       },
       function() {
-        ok(true, "== AddMessageListeners null");
-        addMessageListenersTest(null, {"name1": false, "nameN": true}, 2);
+        info("== AddMessageListeners empty array");
+        addMessageListenersTest([], {
+        "name1": {weakRef: false, count: 1},
+        "nameN": {weakRef: true,  count: 1}
+        }, 2);
         next();
       },
       function() {
-        ok(true, "== AddMessageListeners new listener, string only");
+        info("== AddMessageListeners null");
+        addMessageListenersTest(null, {
+          "name1": {weakRef: false, count: 1},
+          "nameN": {weakRef: true,  count: 1}
+          }, 2);
+        next();
+      },
+      function() {
+        info("== AddMessageListeners new listener, string only");
         addMessageListenersTest("name2", {
-          "name1": false,
-          "name2": false,
-          "nameN": true
+          "name1": {weakRef: false, count: 1},
+          "name2": {weakRef: false, count: 1},
+          "nameN": {weakRef: true,  count: 1}
         }, 3);
         next();
       },
       function() {
-        ok(true, "== AddMessageListeners new listeners, strings array");
+        info("== AddMessageListeners new listeners, strings array");
         addMessageListenersTest(["name3", "name4"], {
-          "name1": false,
-          "name2": false,
-          "name3": false,
-          "name4": false,
-          "nameN": true
+          "name1": {weakRef: false, count: 1},
+          "name2": {weakRef: false, count: 1},
+          "name3": {weakRef: false, count: 1},
+          "name4": {weakRef: false, count: 1},
+          "nameN": {weakRef: true,  count: 1}
         }, 5);
         next();
       },
       function() {
-        ok(true, "== AddMessageListeners new listeners, objects array");
+        info("== AddMessageListeners new listeners, objects array");
         addMessageListenersTest([{
           name: "name5",
           weakRef: true
         }, {
           name: "name6",
           weakRef: false
         }], {
-          "name1": false,
-          "name2": false,
-          "name3": false,
-          "name4": false,
-          "name5": true,
-          "name6": false,
-          "nameN": true
+          "name1": {weakRef: false, count: 1},
+          "name2": {weakRef: false, count: 1},
+          "name3": {weakRef: false, count: 1},
+          "name4": {weakRef: false, count: 1},
+          "name5": {weakRef: true,  count: 1},
+          "name6": {weakRef: false, count: 1},
+          "nameN": {weakRef: true,  count: 1}
         }, 7);
         next();
       },
       function() {
-        ok(true, "== RemoveMessageListeners, null");
+        info("== RemoveMessageListeners, null");
         removeMessageListenersTest(null, {
-          "name1": false,
-          "name2": false,
-          "name3": false,
-          "name4": false,
-          "name5": true,
-          "name6": false,
-          "nameN": true
+          "name1": {weakRef: false, count: 1},
+          "name2": {weakRef: false, count: 1},
+          "name3": {weakRef: false, count: 1},
+          "name4": {weakRef: false, count: 1},
+          "name5": {weakRef: true,  count: 1},
+          "name6": {weakRef: false, count: 1},
+          "nameN": {weakRef: true,  count: 1}
         }, 7);
         next();
       },
       function() {
-        ok(true, "== RemoveMessageListeners, one message");
+        info("== RemoveMessageListeners, one message");
         removeMessageListenersTest("name1", {
-          "name2": false,
-          "name3": false,
-          "name4": false,
-          "name5": true,
-          "name6": false,
-          "nameN": true
+          "name2": {weakRef: false, count: 1},
+          "name3": {weakRef: false, count: 1},
+          "name4": {weakRef: false, count: 1},
+          "name5": {weakRef: true,  count: 1},
+          "name6": {weakRef: false, count: 1},
+          "nameN": {weakRef: true,  count: 1}
         }, 6);
         next();
       },
       function() {
-        ok(true, "== RemoveMessageListeners, array of messages");
+        info("== RemoveMessageListeners, array of messages");
         removeMessageListenersTest(["name2", "name3"], {
-          "name4": false,
-          "name5": true,
-          "name6": false,
-          "nameN": true
+          "name4": {weakRef: false, count: 1},
+          "name5": {weakRef: true,  count: 1},
+          "name6": {weakRef: false, count: 1},
+          "nameN": {weakRef: true,  count: 1}
         }, 4);
         next();
       },
       function() {
-        ok(true, "== RemoveMessageListeners, unknown message");
+        info("== RemoveMessageListeners, unknown message");
         removeMessageListenersTest("unknown", {
-          "name4": false,
-          "name5": true,
-          "name6": false,
-          "nameN": true
+          "name4": {weakRef: false, count: 1},
+          "name5": {weakRef: true,  count: 1},
+          "name6": {weakRef: false, count: 1},
+          "nameN": {weakRef: true,  count: 1}
         }, 4);
         next();
       },
       function() {
         try {
-          ok(true, "== AddMessageListeners, same message, same kind");
+          info("== AddMessageListeners, same message, same kind");
           addMessageListenersTest("name4", {
-            "name4": false,
-            "name5": true,
-            "name6": false,
-            "nameN": true
+            "name4": {weakRef: false, count: 2},
+            "name5": {weakRef: true,  count: 1},
+            "name6": {weakRef: false, count: 1},
+            "nameN": {weakRef: true,  count: 1}
           }, 4);
           next();
         } catch (ex) {
           ok(false, "Unexpected exception " + ex);
         }
       },
       function() {
-        ok(true, "== AddMessageListeners, same message, different kind");
+        info("== AddMessageListeners, same message, different kind");
         try {
           addMessageListenersTest({name: "name4", weakRef: true}, {
-            "name4": true,
-            "name5": true,
-            "name6": false,
-            "nameN": true
+            "name4": {weakRef: false, count: 2},
+            "name5": {weakRef: true,  count: 1},
+            "name6": {weakRef: false, count: 1},
+            "nameN": {weakRef: true,  count: 1}
           }, 4);
           ok(false, "Should have thrown an exception");
         } catch (ex) {
           ok(true, "Expected exception");
           next();
         }
       },
       function() {
-        ok(true, "== Test createRequest()");
+        info("== RemoveMessageListeners, message with two listeners");
+        try {
+          removeMessageListenersTest(["name4", "name5"], {
+            "name4": {weakRef: false, count: 1},
+            "name6": {weakRef: false, count: 1},
+            "nameN": {weakRef: true,  count: 1}
+          }, 3);
+          next();
+        } catch (ex) {
+          ok(false, "Unexpected exception " + ex);
+        }
+      },
+      function() {
+        info("== Test createRequest()");
         ok(DOMRequest, "DOMRequest object exists");
         var req = dummy.createRequest();
         ok(req instanceof DOMRequest, "Returned a DOMRequest");
         next();
       },
       function() {
-        ok(true, "== Test getRequestId(), removeRequest() and getRequest()");
+        info("== Test getRequestId(), removeRequest() and getRequest()");
         var req = dummy.createRequest();
         var id = dummy.getRequestId(req);
         is(typeof id, "string", "id is a string");
         var req_ = dummy.getRequest(id);
         is(req, req_, "Got correct request");
         dummy.removeRequest(id);
         req = dummy.getRequest(id);
         is(req, null, "No request");
         next();
       },
       function() {
-        ok(true, "== Test createPromise()");
+        info("== Test createPromise()");
         ok(Promise, "Promise object exists");
         var promise = dummy.createPromise(function(resolve, reject) {
           resolve(true);
         });
         ok(promise instanceof Promise, "Returned a Promise");
         promise.then(next);
       },
       function() {
-        ok(true, "== Test getResolver()");
+        info("== Test getResolver()");
         var id;
         var resolver;
         var promise = dummy.createPromise(function(resolve, reject) {
           var r = { resolve: resolve, reject: reject };
           id = dummy.getPromiseResolverId(r);
           resolver = r;
           ok(typeof id === "string", "id is a string");
           r.resolve(true);
         }).then(function(unused) {
           var r = dummy.getPromiseResolver(id);
           ok(resolver === r, "Get succeeded");
           next();
         });
       },
       function() {
-        ok(true, "== Test removeResolver");
+        info("== Test removeResolver");
         var id;
         var promise = dummy.createPromise(function(resolve, reject) {
           var r = { resolve: resolve, reject: reject };
           id = dummy.getPromiseResolverId(r);
           ok(typeof id === "string", "id is a string");
 
           var resolver = dummy.getPromiseResolver(id);
-          ok(true, "Got resolver " + JSON.stringify(resolver));
+          info("Got resolver " + JSON.stringify(resolver));
           ok(resolver === r, "Resolver get succeeded");
 
           r.resolve(true);
         }).then(function(unused) {
           dummy.removePromiseResolver(id);
           var resolver = dummy.getPromiseResolver(id);
           ok(resolver === undefined, "removeResolver: get failed");
           next();
         });
       },
       function() {
-        ok(true, "== Test takeResolver");
+        info("== Test takeResolver");
         var id;
         var resolver;
         var promise = dummy.createPromise(function(resolve, reject) {
           var r = { resolve: resolve, reject: reject };
           id = dummy.getPromiseResolverId(r);
           resolver = r;
           ok(typeof id === "string", "id is a string");
 
@@ -414,55 +439,55 @@
           ok(resolver === r, "take should succeed");
 
           r = dummy.getPromiseResolver(id);
           ok(r === undefined, "takeResolver: get failed");
           next();
         });
       },
       function() {
-        ok(true, "== Test window destroyed without messages and without GC");
+        info("== Test window destroyed without messages and without GC");
         checkWindowDestruction({ gc: false }, function(uninitCalled) {
           ok(uninitCalled, "uninit() should have been called");
           next();
         });
       },
       function() {
-        ok(true, "== Test window destroyed without messages and with GC");
+        info("== Test window destroyed without messages and with GC");
         checkWindowDestruction({ gc: true }, function(uninitCalled) {
           ok(!uninitCalled, "uninit() should NOT have been called");
           next();
         });
       },
       function() {
-        ok(true, "== Test window destroyed with weak messages and without GC");
+        info("== Test window destroyed with weak messages and without GC");
         checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
                                  gc: false }, function(uninitCalled) {
           ok(uninitCalled, "uninit() should have been called");
           next();
         });
       },
       function() {
-        ok(true, "== Test window destroyed with weak messages and with GC");
+        info("== Test window destroyed with weak messages and with GC");
         checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
                                  gc: true }, function(uninitCalled) {
           ok(!uninitCalled, "uninit() should NOT have been called");
           next();
         });
       },
       function() {
-        ok(true, "== Test window destroyed with strong messages and without GC");
+        info("== Test window destroyed with strong messages and without GC");
         checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
                                  gc: false }, function(uninitCalled) {
           ok(uninitCalled, "uninit() should have been called");
           next();
         });
       },
       function() {
-        ok(true, "== Test window destroyed with strong messages and with GC");
+        info("== Test window destroyed with strong messages and with GC");
         checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
                                  gc: true }, function(uninitCalled) {
           ok(uninitCalled, "uninit() should have been called");
           next();
         });
       }
     ];
 
--- a/dom/bluetooth/BluetoothRilListener.cpp
+++ b/dom/bluetooth/BluetoothRilListener.cpp
@@ -176,16 +176,19 @@ MobileConnectionListener::Listen(bool aS
  */
 NS_IMPL_ISUPPORTS(TelephonyListener, nsITelephonyListener)
 
 NS_IMETHODIMP
 TelephonyListener::CallStateChanged(uint32_t aServiceId,
                                     uint32_t aCallIndex,
                                     uint16_t aCallState,
                                     const nsAString& aNumber,
+                                    uint16_t aNumberPresentation,
+                                    const nsAString& aName,
+                                    uint16_t aNamePresentation,
                                     bool aIsOutgoing,
                                     bool aIsEmergency,
                                     bool aIsConference,
                                     bool aIsSwitchable,
                                     bool aIsMergeable)
 {
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
   NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE);
@@ -195,16 +198,19 @@ TelephonyListener::CallStateChanged(uint
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyListener::EnumerateCallState(uint32_t aServiceId,
                                       uint32_t aCallIndex,
                                       uint16_t aCallState,
                                       const nsAString_internal& aNumber,
+                                      uint16_t aNumberPresentation,
+                                      const nsAString& aName,
+                                      uint16_t aNamePresentation,
                                       bool aIsOutgoing,
                                       bool aIsEmergency,
                                       bool aIsConference,
                                       bool aIsSwitchable,
                                       bool aIsMergeable)
 {
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
   NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE);
@@ -265,17 +271,20 @@ TelephonyListener::NotifyConferenceError
   BT_WARNING(NS_ConvertUTF16toUTF8(aName).get());
   BT_WARNING(NS_ConvertUTF16toUTF8(aMessage).get());
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyListener::NotifyCdmaCallWaiting(uint32_t aServiceId,
-                                         const nsAString& aNumber)
+                                         const nsAString& aNumber,
+                                         uint16_t aNumberPresentation,
+                                         const nsAString& aName,
+                                         uint16_t aNamePresentation)
 {
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
   NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE);
 
   hfp->UpdateSecondNumber(aNumber);
 
   return NS_OK;
 }
--- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
@@ -45,22 +45,22 @@
 using namespace mozilla;
 using namespace mozilla::ipc;
 USING_BLUETOOTH_NAMESPACE
 
 // TODO: Non thread-safe static variables
 static nsString sAdapterBdAddress;
 static nsString sAdapterBdName;
 static InfallibleTArray<nsString> sAdapterBondedAddressArray;
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeAdapterStateRunnableArray;
 
 // Static variables below should only be used on *main thread*
 static const bt_interface_t* sBtInterface;
 static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
 static nsTArray<int> sRequestedDeviceCountArray;
+static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeAdapterStateRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
 
 // Static variables below should only be used on *callback thread*
 
@@ -290,16 +290,37 @@ PlayStatusStringToControlPlayStatus(cons
     playStatus = ControlPlayStatus::PLAYSTATUS_REV_SEEK;
   } else if (aPlayStatus.EqualsLiteral("ERROR")) {
     playStatus = ControlPlayStatus::PLAYSTATUS_ERROR;
   }
 
   return playStatus;
 }
 
+class AdapterStateChangedCallbackTask MOZ_FINAL : public nsRunnable
+{
+public:
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    // Resolve promise if existed
+    if (!sChangeAdapterStateRunnableArray.IsEmpty()) {
+      BluetoothValue values(true);
+      DispatchBluetoothReply(sChangeAdapterStateRunnableArray[0],
+                             values, EmptyString());
+
+      sChangeAdapterStateRunnableArray.RemoveElementAt(0);
+    }
+
+    return NS_OK;
+  }
+};
+
 /**
  *  Bluedroid HAL callback functions
  *
  *  Several callbacks are dispatched to main thread to avoid racing issues.
  */
 static void
 AdapterStateChangeCallback(bt_state_t aStatus)
 {
@@ -322,23 +343,18 @@ AdapterStateChangeCallback(bt_state_t aS
   }
 
   if (sAdapterEnabled &&
       NS_FAILED(NS_DispatchToMainThread(new SetupAfterEnabledTask()))) {
     BT_WARNING("Failed to dispatch to main thread!");
     return;
   }
 
-  // Resolve promise if existed
-  if(!sChangeAdapterStateRunnableArray.IsEmpty()) {
-    DispatchBluetoothReply(sChangeAdapterStateRunnableArray[0],
-                           BluetoothValue(true),
-                           EmptyString());
-    sChangeAdapterStateRunnableArray.RemoveElementAt(0);
-  }
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(new AdapterStateChangedCallbackTask());
 }
 
 class AdapterPropertiesCallbackTask MOZ_FINAL : public nsRunnable
 {
 public:
   NS_IMETHOD
   Run()
   {
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -635,22 +635,22 @@ BrowserElementParent.prototype = {
         this.extListener.onStartRequest(aRequest, aContext);
       },
       onStopRequest: function(aRequest, aContext, aStatusCode) {
         debug('DownloadListener - onStopRequest (aStatusCode = ' +
                aStatusCode + ')');
         if (aStatusCode == Cr.NS_OK) {
           // Everything looks great.
           debug('DownloadListener - Download Successful.');
-          this.services.DOMRequest.fireSuccess(this.req, aStatusCode);
+          Services.DOMRequest.fireSuccess(req, aStatusCode);
         }
         else {
           // In case of failure, we'll simply return the failure status code.
           debug('DownloadListener - Download Failed!');
-          this.services.DOMRequest.fireError(this.req, aStatusCode);
+          Services.DOMRequest.fireError(req, aStatusCode);
         }
 
         if (this.extListener) {
           this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
         }
       },
       onDataAvailable: function(aRequest, aContext, aInputStream,
                                 aOffset, aCount) {
--- a/dom/nfc/tests/marionette/test_nfc_peer.js
+++ b/dom/nfc/tests/marionette/test_nfc_peer.js
@@ -54,40 +54,28 @@ function handleTechnologyDiscoveredRE0Fo
   request.onerror = function () {
     ok(false, "checkP2PRegistration failed.");
 
     nfc.onpeerready = null;
     toggleNFC(false).then(runNextTest);
   }
 }
 
-function activateRE(re) {
-  let deferred = Promise.defer();
-  let cmd = "nfc nci rf_intf_activated_ntf " + re;
-
-  emulator.run(cmd, function(result) {
-    is(result.pop(), "OK", "check activation of RE" + re);
-    deferred.resolve();
-  });
-
-  return deferred.promise;
-}
-
 function testPeerReady() {
   window.navigator.mozSetMessageHandler(
     "nfc-manager-tech-discovered", handleTechnologyDiscoveredRE0);
 
-  toggleNFC(true).then(() => activateRE(0));
+  toggleNFC(true).then(() => emulator.activateRE(0));
 }
 
 function testCheckP2PRegFailure() {
   window.navigator.mozSetMessageHandler(
     "nfc-manager-tech-discovered", handleTechnologyDiscoveredRE0ForP2PRegFailure);
 
-  toggleNFC(true).then(() => activateRE(0));
+  toggleNFC(true).then(() => emulator.activateRE(0));
 }
 
 function testCheckNfcPeerObjForInvalidToken() {
   try {
     // Use a'fakeSessionToken'
     let peer = nfc.getNFCPeer("fakeSessionToken");
     ok(false, "Should not get a NFCPeer object.");
   } catch (ex) {
--- a/dom/nfc/tests/marionette/test_nfc_tag.js
+++ b/dom/nfc/tests/marionette/test_nfc_tag.js
@@ -30,18 +30,18 @@ function testUrlTagDiscover(re) {
     is(tnf, records[0].tnf, "check for TNF field in NDEF");
     is(type, NfcUtils.toUTF8(records[0].type), "check for type field in NDEF");
     is(payload, NfcUtils.toUTF8(records[0].payload), "check for payload field in NDEF");
 
     toggleNFC(false).then(runNextTest);
   });
 
   toggleNFC(true)
-  .then(() => setTagData(re, flag, tnf, btoa(type), btoa(payload)))
-  .then(() => activateRE(re));
+  .then(() => emulator.setTagData(re, flag, tnf, btoa(type), btoa(payload)))
+  .then(() => emulator.activateRE(re));
 }
 
 function testUrlT1TDiscover() {
   testUrlTagDiscover(T1T_RE_INDEX);
 }
 
 function testUrlT2TDiscover() {
   testUrlTagDiscover(T2T_RE_INDEX);
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -2070,17 +2070,17 @@ RadioInterface.prototype = {
         break;
       case "callDisconnected":
         gTelephonyService.notifyCallDisconnected(this.clientId, message.call);
         break;
       case "conferenceCallStateChanged":
         gTelephonyService.notifyConferenceCallStateChanged(message.state);
         break;
       case "cdmaCallWaiting":
-        gTelephonyService.notifyCdmaCallWaiting(this.clientId, message.number);
+        gTelephonyService.notifyCdmaCallWaiting(this.clientId, message.waitingCall);
         break;
       case "suppSvcNotification":
         gTelephonyService.notifySupplementaryService(this.clientId,
                                                       message.callIndex,
                                                       message.notification);
         break;
       case "datacallerror":
         connHandler.handleDataCallError(message);
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -359,20 +359,34 @@ this.GECKO_CARD_TYPE = [
   null,
   "sim",
   "usim",
   "ruim",
   "csim",
   "isim"
 ];
 
-this.NETWORK_STATE_UNKNOWN = "unknown";
-this.NETWORK_STATE_AVAILABLE = "available";
-this.NETWORK_STATE_CONNECTED = "connected";
-this.NETWORK_STATE_FORBIDDEN = "forbidden";
+
+// Used for QUERY_AVAILABLE_NETWORKS status.
+this.QAN_STATE_UNKNOWN   = "unknown";
+this.QAN_STATE_AVAILABLE = "available";
+this.QAN_STATE_CURRENT   = "current";
+this.QAN_STATE_FORBIDDEN = "forbidden";
+
+// Must be in sync with MobileNetworkState of MozMobileNetworkInfo.webidl
+this.GECKO_QAN_STATE_UNKNOWN   = null;
+this.GECKO_QAN_STATE_AVAILABLE = "available";
+this.GECKO_QAN_STATE_CONNECTED = "connected";
+this.GECKO_QAN_STATE_FORBIDDEN = "forbidden";
+
+this.RIL_QAN_STATE_TO_GECKO_STATE = {};
+this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_UNKNOWN]   = this.GECKO_QAN_STATE_UNKNOWN;
+this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_AVAILABLE] = this.GECKO_QAN_STATE_AVAILABLE;
+this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_CURRENT]   = this.GECKO_QAN_STATE_CONNECTED;
+this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_FORBIDDEN] = this.GECKO_QAN_STATE_FORBIDDEN;
 
 this.NETWORK_SELECTION_MODE_AUTOMATIC = 0;
 this.NETWORK_SELECTION_MODE_MANUAL = 1;
 
 this.NETWORK_INFO_VOICE_REGISTRATION_STATE = "voiceRegistrationState";
 this.NETWORK_INFO_DATA_REGISTRATION_STATE = "dataRegistrationState";
 this.NETWORK_INFO_OPERATOR = "operator";
 this.NETWORK_INFO_NETWORK_SELECTION_MODE = "networkSelectionMode";
@@ -2390,19 +2404,16 @@ this.DATACALL_FAIL_ERROR_UNSPECIFIED = 0
 
 // Keep consistent with nsINetworkManager.NETWORK_STATE_*.
 this.GECKO_NETWORK_STATE_UNKNOWN = -1;
 this.GECKO_NETWORK_STATE_CONNECTING = 0;
 this.GECKO_NETWORK_STATE_CONNECTED = 1;
 this.GECKO_NETWORK_STATE_DISCONNECTING = 2;
 this.GECKO_NETWORK_STATE_DISCONNECTED = 3;
 
-// Used for QUERY_AVAILABLE_NETWORKS status of "unknown"
-this.GECKO_QAN_STATE_UNKNOWN = null;
-
 this.CALL_FAIL_UNOBTAINABLE_NUMBER = 1;
 this.CALL_FAIL_NORMAL = 16;
 this.CALL_FAIL_BUSY = 17;
 this.CALL_FAIL_NO_USER_RESPONDING = 18;
 this.CALL_FAIL_USER_ALERTING = 19;
 this.CALL_FAIL_CALL_REJECTED = 21;
 this.CALL_FAIL_NUMBER_CHANGED = 22;
 this.CALL_FAIL_CALL_PRE_EMPTION = 25;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -4456,23 +4456,18 @@ RilObject.prototype = {
       let networkTuple = strings[i + 2];
       try {
         this._processNetworkTuple(networkTuple, network);
       } catch (e) {
         if (DEBUG) this.context.debug("Error processing operator tuple: " + e);
       }
 
       let state = strings[i + 3];
-      if (state === NETWORK_STATE_UNKNOWN) {
-        // TODO: looks like this might conflict in style with
-        // GECKO_NETWORK_STYLE_UNKNOWN / nsINetworkManager
-        state = GECKO_QAN_STATE_UNKNOWN;
-      }
-
-      network.state = state;
+      network.state = RIL_QAN_STATE_TO_GECKO_STATE[state];
+
       networks.push(network);
     }
     return networks;
   },
 
   /**
    * The "numeric" portion of the operator info is a tuple
    * containing MCC (country code) and MNC (network code).
@@ -5524,17 +5519,17 @@ RilObject.prototype[REQUEST_GET_CURRENT_
     call.isMpty         = Boolean(Buf.readInt32());
     call.isMT           = Boolean(Buf.readInt32());
     call.als            = Buf.readInt32();
     call.isVoice        = Boolean(Buf.readInt32());
     call.isVoicePrivacy = Boolean(Buf.readInt32());
     if (RILQUIRKS_CALLSTATE_EXTRA_UINT32) {
       Buf.readInt32();
     }
-    call.number             = Buf.readString(); //TODO munge with TOA
+    call.number             = Buf.readString();
     call.numberPresentation = Buf.readInt32(); // CALL_PRESENTATION_*
     call.name               = Buf.readString();
     call.namePresentation   = Buf.readInt32();
 
     call.uusInfo = null;
     let uusInfoPresent = Buf.readInt32();
     if (uusInfoPresent == 1) {
       call.uusInfo = {
@@ -6855,17 +6850,17 @@ RilObject.prototype[UNSOLICITED_CDMA_CAL
   call.numberPresentation  = Buf.readInt32();
   call.name                = Buf.readString();
   call.namePresentation    = Buf.readInt32();
   call.isPresent           = Buf.readInt32();
   call.signalType          = Buf.readInt32();
   call.alertPitch          = Buf.readInt32();
   call.signal              = Buf.readInt32();
   this.sendChromeMessage({rilMessageType: "cdmaCallWaiting",
-                          number: call.number});
+                          waitingCall: call});
 };
 RilObject.prototype[UNSOLICITED_CDMA_OTA_PROVISION_STATUS] = function UNSOLICITED_CDMA_OTA_PROVISION_STATUS() {
   let status = this.context.Buf.readInt32List()[0];
   this.sendChromeMessage({rilMessageType: "otastatuschange",
                           status: status});
 };
 RilObject.prototype[UNSOLICITED_CDMA_INFO_REC] = function UNSOLICITED_CDMA_INFO_REC(length) {
   let record = this.context.CdmaPDUHelper.decodeInformationRecord();
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -20,16 +20,17 @@
 #include "nsCxPusher.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 
 #include "CallsList.h"
 #include "TelephonyCall.h"
 #include "TelephonyCallGroup.h"
+#include "TelephonyCallId.h"
 
 using namespace mozilla::dom;
 using mozilla::ErrorResult;
 
 class Telephony::Listener : public nsITelephonyListener
 {
   Telephony* mTelephony;
 
@@ -271,16 +272,19 @@ Telephony::DialInternal(uint32_t aServic
 }
 
 already_AddRefed<TelephonyCall>
 Telephony::CreateNewDialingCall(uint32_t aServiceId, const nsAString& aNumber,
                                 uint32_t aCallIndex)
 {
   nsRefPtr<TelephonyCall> call =
     TelephonyCall::Create(this, aServiceId, aNumber,
+                          nsITelephonyService::CALL_PRESENTATION_ALLOWED,
+                          EmptyString(),
+                          nsITelephonyService::CALL_PRESENTATION_ALLOWED,
                           nsITelephonyService::CALL_STATE_DIALING, aCallIndex);
   NS_ASSERTION(call, "This should never fail!");
 
   NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
 
   return call.forget();
 }
 
@@ -469,18 +473,20 @@ Telephony::EventListenerAdded(nsIAtom* a
   }
 }
 
 // nsITelephonyListener
 
 NS_IMETHODIMP
 Telephony::CallStateChanged(uint32_t aServiceId, uint32_t aCallIndex,
                             uint16_t aCallState, const nsAString& aNumber,
-                            bool aIsOutgoing, bool aIsEmergency,
-                            bool aIsConference, bool aIsSwitchable, bool aIsMergeable)
+                            uint16_t aNumberPresentation, const nsAString& aName,
+                            uint16_t aNamePresentation, bool aIsOutgoing,
+                            bool aIsEmergency, bool aIsConference,
+                            bool aIsSwitchable, bool aIsMergeable)
 {
   nsRefPtr<TelephonyCall> modifiedCall
       = GetCallFromEverywhere(aServiceId, aCallIndex);
 
   if (modifiedCall) {
     modifiedCall->UpdateEmergency(aIsEmergency);
     modifiedCall->UpdateSwitchable(aIsSwitchable);
     modifiedCall->UpdateMergeable(aIsMergeable);
@@ -515,19 +521,20 @@ Telephony::CallStateChanged(uint32_t aSe
   // Do nothing since we didn't know anything about it before now and it's
   // ended already.
   if (aCallState == nsITelephonyService::CALL_STATE_DISCONNECTED) {
     return NS_OK;
   }
 
   // Didn't find this call in mCalls or mGroup. Create a new call.
   nsRefPtr<TelephonyCall> call =
-      TelephonyCall::Create(this, aServiceId, aNumber, aCallState, aCallIndex,
-                            aIsEmergency, aIsConference, aIsSwitchable,
-                            aIsMergeable);
+    TelephonyCall::Create(this, aServiceId, aNumber, aNumberPresentation,
+                          aName, aNamePresentation, aCallState, aCallIndex,
+                          aIsEmergency, aIsConference, aIsSwitchable,
+                          aIsMergeable);
   NS_ASSERTION(call, "This should never fail!");
 
   NS_ASSERTION(aIsConference ? mGroup->CallsArray().Contains(call) :
                                mCalls.Contains(call),
                "Should have auto-added new call!");
 
   if (aCallState == nsITelephonyService::CALL_STATE_INCOMING) {
     nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("incoming"), call);
@@ -559,33 +566,36 @@ Telephony::EnumerateCallStateComplete()
     NS_WARNING("Failed to register listener!");
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::EnumerateCallState(uint32_t aServiceId, uint32_t aCallIndex,
                               uint16_t aCallState, const nsAString& aNumber,
-                              bool aIsOutgoing, bool aIsEmergency,
-                              bool aIsConference, bool aIsSwitchable, bool aIsMergeable)
+                              uint16_t aNumberPresentation, const nsAString& aName,
+                              uint16_t aNamePresentation, bool aIsOutgoing,
+                              bool aIsEmergency, bool aIsConference,
+                              bool aIsSwitchable, bool aIsMergeable)
 {
   nsRefPtr<TelephonyCall> call;
 
   // We request calls enumeration in constructor, and the asynchronous result
   // will be sent back through the callback function EnumerateCallState().
   // However, it is likely to have call state changes, i.e. CallStateChanged()
   // being called, before the enumeration result comes back. We'd make sure
   // we don't somehow add duplicates due to the race condition.
   call = GetCallFromEverywhere(aServiceId, aCallIndex);
   if (call) {
     return NS_OK;
   }
 
   // Didn't know anything about this call before now.
-  call = TelephonyCall::Create(this, aServiceId, aNumber, aCallState,
+  call = TelephonyCall::Create(this, aServiceId, aNumber, aNumberPresentation,
+                               aName, aNamePresentation, aCallState,
                                aCallIndex, aIsEmergency, aIsConference,
                                aIsSwitchable, aIsMergeable);
   NS_ASSERTION(call, "This should never fail!");
 
   NS_ASSERTION(aIsConference ? mGroup->CallsArray().Contains(call) :
                                mCalls.Contains(call),
                "Should have auto-added new call!");
 
@@ -637,24 +647,30 @@ Telephony::NotifyError(uint32_t aService
 
   // Set the call state to 'disconnected' and remove it from the calls list.
   callToNotify->NotifyError(aError);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-Telephony::NotifyCdmaCallWaiting(uint32_t aServiceId, const nsAString& aNumber)
+Telephony::NotifyCdmaCallWaiting(uint32_t aServiceId, const nsAString& aNumber,
+                                 uint16_t aNumberPresentation,
+                                 const nsAString& aName,
+                                 uint16_t aNamePresentation)
 {
   MOZ_ASSERT(mCalls.Length() == 1);
 
   nsRefPtr<TelephonyCall> callToNotify = mCalls[0];
   MOZ_ASSERT(callToNotify && callToNotify->ServiceId() == aServiceId);
 
-  callToNotify->UpdateSecondNumber(aNumber);
+  nsRefPtr<TelephonyCallId> id =
+    new TelephonyCallId(GetOwner(), aNumber, aNumberPresentation, aName,
+                        aNamePresentation);
+  callToNotify->UpdateSecondId(id);
   DispatchCallEvent(NS_LITERAL_STRING("callschanged"), callToNotify);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::NotifyConferenceError(const nsAString& aName,
                                  const nsAString& aMessage)
 {
--- a/dom/telephony/TelephonyCall.cpp
+++ b/dom/telephony/TelephonyCall.cpp
@@ -14,35 +14,39 @@
 #include "TelephonyCallGroup.h"
 
 using namespace mozilla::dom;
 using mozilla::ErrorResult;
 
 // static
 already_AddRefed<TelephonyCall>
 TelephonyCall::Create(Telephony* aTelephony, uint32_t aServiceId,
-                      const nsAString& aNumber, uint16_t aCallState,
-                      uint32_t aCallIndex, bool aEmergency, bool aIsConference,
-                      bool aSwitchable, bool aMergeable)
+                      const nsAString& aNumber, uint16_t aNumberPresentation,
+                      const nsAString& aName, uint16_t aNamePresentation,
+                      uint16_t aCallState, uint32_t aCallIndex, bool aEmergency,
+                      bool aIsConference, bool aSwitchable, bool aMergeable)
 {
   NS_ASSERTION(aTelephony, "Null pointer!");
   NS_ASSERTION(!aNumber.IsEmpty(), "Empty number!");
   NS_ASSERTION(aCallIndex >= 1, "Invalid call index!");
 
   nsRefPtr<TelephonyCall> call = new TelephonyCall(aTelephony->GetOwner());
+  nsRefPtr<TelephonyCallId> id = new TelephonyCallId(aTelephony->GetOwner(),
+                                                     aNumber, aNumberPresentation,
+                                                     aName, aNamePresentation);
 
   call->mTelephony = aTelephony;
   call->mServiceId = aServiceId;
-  call->mNumber = aNumber;
   call->mCallIndex = aCallIndex;
   call->mError = nullptr;
   call->mEmergency = aEmergency;
   call->mGroup = aIsConference ? aTelephony->ConferenceGroup() : nullptr;
   call->mSwitchable = aSwitchable;
   call->mMergeable = aMergeable;
+  call->mId = id;
 
   call->ChangeStateInternal(aCallState, false);
 
   return call.forget();
 }
 
 TelephonyCall::TelephonyCall(nsPIDOMWindow* aOwner)
   : DOMEventTargetHelper(aOwner),
@@ -182,26 +186,42 @@ TelephonyCall::ChangeGroup(TelephonyCall
     NS_WARNING("Failed to dispatch error event!");
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(TelephonyCall,
                                    DOMEventTargetHelper,
                                    mTelephony,
                                    mError,
-                                   mGroup);
+                                   mGroup,
+                                   mId,
+                                   mSecondId);
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TelephonyCall)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(TelephonyCall, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(TelephonyCall, DOMEventTargetHelper)
 
 // TelephonyCall WebIDL
 
+already_AddRefed<TelephonyCallId>
+TelephonyCall::Id() const
+{
+  nsRefPtr<TelephonyCallId> id = mId;
+  return id.forget();
+}
+
+already_AddRefed<TelephonyCallId>
+TelephonyCall::GetSecondId() const
+{
+  nsRefPtr<TelephonyCallId> id = mSecondId;
+  return id.forget();
+}
+
 already_AddRefed<DOMError>
 TelephonyCall::GetError() const
 {
   nsRefPtr<DOMError> error = mError;
   return error.forget();
 }
 
 already_AddRefed<TelephonyCallGroup>
@@ -267,17 +287,17 @@ TelephonyCall::Hold(ErrorResult& aRv)
   }
 
   nsresult rv = mTelephony->Service()->HoldCall(mServiceId, mCallIndex);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
-  if (!mSecondNumber.IsEmpty()) {
+  if (mSecondId) {
     // No state transition when we switch two numbers within one TelephonyCall
     // object. Otherwise, the state here will be inconsistent with the backend
     // RIL and will never be right.
     return;
   }
 
   ChangeStateInternal(nsITelephonyService::CALL_STATE_HOLDING, true);
 }
--- a/dom/telephony/TelephonyCall.h
+++ b/dom/telephony/TelephonyCall.h
@@ -6,69 +6,65 @@
 
 #ifndef mozilla_dom_telephony_telephonycall_h__
 #define mozilla_dom_telephony_telephonycall_h__
 
 #include "mozilla/dom/telephony/TelephonyCommon.h"
 
 #include "mozilla/dom/DOMError.h"
 
+#include "TelephonyCallId.h"
+
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class TelephonyCall MOZ_FINAL : public DOMEventTargetHelper
 {
   nsRefPtr<Telephony> mTelephony;
   nsRefPtr<TelephonyCallGroup> mGroup;
 
+  nsRefPtr<TelephonyCallId> mId;
+  nsRefPtr<TelephonyCallId> mSecondId;
+
   uint32_t mServiceId;
-  nsString mNumber;
-  nsString mSecondNumber;
   nsString mState;
   bool mEmergency;
   nsRefPtr<DOMError> mError;
   bool mSwitchable;
   bool mMergeable;
 
   uint32_t mCallIndex;
   uint16_t mCallState;
   bool mLive;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TelephonyCall,
                                            DOMEventTargetHelper)
-
   friend class Telephony;
 
   nsPIDOMWindow*
   GetParentObject() const
   {
     return GetOwner();
   }
 
   // WrapperCache
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   // WebIDL
-  void
-  GetNumber(nsString& aNumber) const
-  {
-    aNumber.Assign(mNumber);
-  }
+  already_AddRefed<TelephonyCallId>
+  Id() const;
 
-  void
-  GetSecondNumber(nsString& aSecondNumber) const
-  {
-    aSecondNumber.Assign(mSecondNumber);
-  }
+  already_AddRefed<TelephonyCallId>
+  GetSecondId() const;
 
   void
   GetState(nsString& aState) const
   {
     aState.Assign(mState);
   }
 
   bool
@@ -117,17 +113,19 @@ public:
   IMPL_EVENT_HANDLER(holding)
   IMPL_EVENT_HANDLER(held)
   IMPL_EVENT_HANDLER(resuming)
   IMPL_EVENT_HANDLER(error)
   IMPL_EVENT_HANDLER(groupchange)
 
   static already_AddRefed<TelephonyCall>
   Create(Telephony* aTelephony, uint32_t aServiceId,
-         const nsAString& aNumber, uint16_t aCallState, uint32_t aCallIndex,
+         const nsAString& aNumber, uint16_t aNumberPresentation,
+         const nsAString& aName, uint16_t aNamePresentation,
+         uint16_t aCallState, uint32_t aCallIndex,
          bool aEmergency = false, bool aIsConference = false,
          bool aSwitchable = true, bool aMergeable = true);
 
   void
   ChangeState(uint16_t aCallState)
   {
     ChangeStateInternal(aCallState, true);
   }
@@ -152,32 +150,31 @@ public:
 
   void
   UpdateEmergency(bool aEmergency)
   {
     mEmergency = aEmergency;
   }
 
   void
-  UpdateSecondNumber(const nsAString& aNumber)
-  {
-    mSecondNumber = aNumber;
-  }
-
-  void
   UpdateSwitchable(bool aSwitchable) {
     mSwitchable = aSwitchable;
   }
 
   void
   UpdateMergeable(bool aMergeable) {
     mMergeable = aMergeable;
   }
 
   void
+  UpdateSecondId(TelephonyCallId* aId) {
+    mSecondId = aId;
+  }
+
+  void
   NotifyError(const nsAString& aError);
 
   void
   ChangeGroup(TelephonyCallGroup* aGroup);
 
 private:
   TelephonyCall(nsPIDOMWindow* aOwner);
 
new file mode 100644
--- /dev/null
+++ b/dom/telephony/TelephonyCallId.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#include "TelephonyCallId.h"
+
+#include "nsITelephonyService.h"
+
+namespace mozilla {
+namespace dom {
+
+TelephonyCallId::TelephonyCallId(nsPIDOMWindow* aWindow,
+                                 const nsAString& aNumber,
+                                 uint16_t aNumberPresentation,
+                                 const nsAString& aName,
+                                 uint16_t aNamePresentation)
+: mWindow(aWindow), mNumber(aNumber), mNumberPresentation(aNumberPresentation),
+  mName(aName), mNamePresentation(aNamePresentation)
+{
+  SetIsDOMBinding();
+}
+
+TelephonyCallId::~TelephonyCallId()
+{
+}
+
+JSObject*
+TelephonyCallId::WrapObject(JSContext* aCx)
+{
+  return TelephonyCallIdBinding::Wrap(aCx, this);
+}
+
+CallIdPresentation
+TelephonyCallId::GetPresentationStr(uint16_t aPresentation) const
+{
+  switch (aPresentation) {
+    case nsITelephonyService::CALL_PRESENTATION_ALLOWED:
+      return CallIdPresentation::Allowed;
+    case nsITelephonyService::CALL_PRESENTATION_RESTRICTED:
+      return CallIdPresentation::Restricted;
+    case nsITelephonyService::CALL_PRESENTATION_UNKNOWN:
+      return CallIdPresentation::Unknown;
+    case nsITelephonyService::CALL_PRESENTATION_PAYPHONE:
+      return CallIdPresentation::Payphone;
+    default:
+      MOZ_ASSUME_UNREACHABLE("Bad presentation!");
+  }
+}
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TelephonyCallId, mWindow)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TelephonyCallId)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TelephonyCallId)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TelephonyCallId)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+// WebIDL
+
+CallIdPresentation
+TelephonyCallId::NumberPresentation() const
+{
+  return GetPresentationStr(mNumberPresentation);
+}
+
+CallIdPresentation
+TelephonyCallId::NamePresentation() const
+{
+  return GetPresentationStr(mNamePresentation);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/telephony/TelephonyCallId.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#ifndef mozilla_dom_TelephonyCallId_h
+#define mozilla_dom_TelephonyCallId_h
+
+#include "mozilla/dom/TelephonyCallIdBinding.h"
+#include "mozilla/dom/telephony/TelephonyCommon.h"
+
+#include "nsWrapperCache.h"
+
+class nsPIDOMWindow;
+
+namespace mozilla {
+namespace dom {
+
+class TelephonyCallId MOZ_FINAL : public nsISupports,
+                                  public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TelephonyCallId)
+
+  TelephonyCallId(nsPIDOMWindow* aWindow, const nsAString& aNumber,
+                  uint16_t aNumberPresentation, const nsAString& aName,
+                  uint16_t aNamePresentation);
+
+  nsPIDOMWindow*
+  GetParentObject() const
+  {
+    return mWindow;
+  }
+
+  virtual JSObject*
+  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  // WebIDL
+
+  void
+  GetNumber(nsString& aNumber) const
+  {
+    aNumber.Assign(mNumber);
+  }
+
+  CallIdPresentation
+  NumberPresentation() const;
+
+  void
+  GetName(nsString& aName) const
+  {
+    aName.Assign(mName);
+  }
+
+  CallIdPresentation
+  NamePresentation() const;
+
+private:
+  ~TelephonyCallId();
+
+  nsCOMPtr<nsPIDOMWindow> mWindow;
+  nsString mNumber;
+  uint16_t mNumberPresentation;
+  nsString mName;
+  uint16_t mNamePresentation;
+
+  CallIdPresentation
+  GetPresentationStr(uint16_t aPresentation) const;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_TelephonyCallId_h
--- a/dom/telephony/gonk/TelephonyService.js
+++ b/dom/telephony/gonk/TelephonyService.js
@@ -356,17 +356,19 @@ TelephonyService.prototype = {
     for (let cid = 0; cid < this._numClients; ++cid) {
       let calls = this._currentCalls[cid];
       if (!calls) {
         continue;
       }
       for (let i = 0, indexes = Object.keys(calls); i < indexes.length; ++i) {
         let call = calls[indexes[i]];
         aListener.enumerateCallState(call.clientId, call.callIndex,
-                                     call.state, call.number, call.isOutgoing,
+                                     call.state, call.number,
+                                     call.numberPresentation, call.name,
+                                     call.namePresentation, call.isOutgoing,
                                      call.isEmergency, call.isConference,
                                      call.isSwitchable, call.isMergeable);
       }
     }
     aListener.enumerateCallStateComplete();
   },
 
   isDialing: false,
@@ -724,16 +726,19 @@ TelephonyService.prototype = {
     this._updateActiveCall(aCall);
 
     if (!aCall.failCause ||
         aCall.failCause === RIL.GECKO_CALL_ERROR_NORMAL_CALL_CLEARING) {
       this._notifyAllListeners("callStateChanged", [aClientId,
                                                     aCall.callIndex,
                                                     aCall.state,
                                                     aCall.number,
+                                                    aCall.numberPresentation,
+                                                    aCall.name,
+                                                    aCall.namePresentation,
                                                     aCall.isOutgoing,
                                                     aCall.isEmergency,
                                                     aCall.isConference,
                                                     aCall.isSwitchable,
                                                     aCall.isMergeable]);
     } else {
       this._notifyAllListeners("notifyError",
                                [aClientId, aCall.callIndex, aCall.failCause]);
@@ -788,42 +793,56 @@ TelephonyService.prototype = {
                          aCall.isMergeable : call.isMergeable;
     } else {
       call = aCall;
       call.isSwitchable = aCall.isSwitchable != null ?
                           aCall.isSwitchable : true;
       call.isMergeable = aCall.isMergeable != null ?
                          aCall.isMergeable : true;
 
+      call.numberPresentation = aCall.numberPresentation != null ?
+                                aCall.numberPresentation : nsITelephonyService.CALL_PRESENTATION_ALLOWED;
+      call.name = aCall.name != null ?
+                  aCall.name : "";
+      call.namePresentation = aCall.namePresentation != null ?
+                              aCall.namePresentation : nsITelephonyService.CALL_PRESENTATION_ALLOWED;
+
       this._currentCalls[aClientId][aCall.callIndex] = call;
     }
 
     this._notifyAllListeners("callStateChanged", [aClientId,
                                                   call.callIndex,
                                                   call.state,
                                                   call.number,
+                                                  call.numberPresentation,
+                                                  call.name,
+                                                  call.namePresentation,
                                                   call.isOutgoing,
                                                   call.isEmergency,
                                                   call.isConference,
                                                   call.isSwitchable,
                                                   call.isMergeable]);
   },
 
-  notifyCdmaCallWaiting: function(aClientId, aNumber) {
+  notifyCdmaCallWaiting: function(aClientId, aCall) {
     // We need to acquire a CPU wake lock to avoid the system falling into
     // the sleep mode when the RIL handles the incoming call.
     this._acquireCallRingWakeLock();
 
     let call = this._currentCalls[aClientId][CDMA_SECOND_CALL_INDEX];
     if (call) {
       // TODO: Bug 977503 - B2G RIL: [CDMA] update callNumber when a waiting
       // call comes after a 3way call.
       this.notifyCallDisconnected(aClientId, call);
     }
-    this._notifyAllListeners("notifyCdmaCallWaiting", [aClientId, aNumber]);
+    this._notifyAllListeners("notifyCdmaCallWaiting", [aClientId,
+                                                       aCall.number,
+                                                       aCall.numberPresentation,
+                                                       aCall.name,
+                                                       aCall.namePresentation]);
   },
 
   notifySupplementaryService: function(aClientId, aCallIndex, aNotification) {
     let notification = this._convertRILSuppSvcNotification(aNotification);
     this._notifyAllListeners("supplementaryServiceNotification",
                              [aClientId, aCallIndex, notification]);
   },
 
--- a/dom/telephony/ipc/PTelephony.ipdl
+++ b/dom/telephony/ipc/PTelephony.ipdl
@@ -34,17 +34,17 @@ sync protocol PTelephony {
   manager PContent;
   manages PTelephonyRequest;
 
 child:
   NotifyCallError(uint32_t aClientId, int32_t aCallIndex, nsString aError);
 
   NotifyCallStateChanged(uint32_t aClientId, IPCCallStateData aData);
 
-  NotifyCdmaCallWaiting(uint32_t aClientId, nsString aNumber);
+  NotifyCdmaCallWaiting(uint32_t aClientId, IPCCdmaWaitingCallData aData);
 
   NotifyConferenceCallStateChanged(uint16_t aCallState);
 
   NotifyConferenceError(nsString aName, nsString aMessage);
 
   NotifySupplementaryService(uint32_t aClientId, int32_t aCallIndex,
                              uint16_t aNotification);
 
--- a/dom/telephony/ipc/TelephonyChild.cpp
+++ b/dom/telephony/ipc/TelephonyChild.cpp
@@ -60,31 +60,38 @@ TelephonyChild::RecvNotifyCallStateChang
                                            const IPCCallStateData& aData)
 {
   MOZ_ASSERT(mService);
 
   mService->CallStateChanged(aClientId,
                               aData.callIndex(),
                               aData.callState(),
                               aData.number(),
+                              aData.numberPresentation(),
+                              aData.name(),
+                              aData.namePresentation(),
                               aData.isOutGoing(),
                               aData.isEmergency(),
                               aData.isConference(),
                               aData.isSwitchable(),
                               aData.isMergeable());
   return true;
 }
 
 bool
 TelephonyChild::RecvNotifyCdmaCallWaiting(const uint32_t& aClientId,
-                                          const nsString& aNumber)
+                                          const IPCCdmaWaitingCallData& aData)
 {
   MOZ_ASSERT(mService);
 
-  mService->NotifyCdmaCallWaiting(aClientId, aNumber);
+  mService->NotifyCdmaCallWaiting(aClientId,
+                                  aData.number(),
+                                  aData.numberPresentation(),
+                                  aData.name(),
+                                  aData.namePresentation());
   return true;
 }
 
 bool
 TelephonyChild::RecvNotifyConferenceCallStateChanged(const uint16_t& aCallState)
 {
   MOZ_ASSERT(mService);
 
@@ -153,16 +160,19 @@ TelephonyRequestChild::RecvNotifyEnumera
                                                     const IPCCallStateData& aData)
 {
   MOZ_ASSERT(mListener);
 
   mListener->EnumerateCallState(aClientId,
                                 aData.callIndex(),
                                 aData.callState(),
                                 aData.number(),
+                                aData.numberPresentation(),
+                                aData.name(),
+                                aData.namePresentation(),
                                 aData.isOutGoing(),
                                 aData.isEmergency(),
                                 aData.isConference(),
                                 aData.isSwitchable(),
                                 aData.isMergeable());
   return true;
 }
 
--- a/dom/telephony/ipc/TelephonyChild.h
+++ b/dom/telephony/ipc/TelephonyChild.h
@@ -37,17 +37,17 @@ protected:
                       const nsString& aError) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyCallStateChanged(const uint32_t& aClientId,
                              const IPCCallStateData& aData) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyCdmaCallWaiting(const uint32_t& aClientId,
-                            const nsString& aNumber) MOZ_OVERRIDE;
+                            const IPCCdmaWaitingCallData& aData) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyConferenceCallStateChanged(const uint16_t& aCallState) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyConferenceError(const nsString& aName,
                             const nsString& aMessage) MOZ_OVERRIDE;
 
--- a/dom/telephony/ipc/TelephonyIPCService.cpp
+++ b/dom/telephony/ipc/TelephonyIPCService.cpp
@@ -350,24 +350,28 @@ TelephonyIPCService::SetSpeakerEnabled(b
 
 // nsITelephonyListener
 
 NS_IMETHODIMP
 TelephonyIPCService::CallStateChanged(uint32_t aClientId,
                                        uint32_t aCallIndex,
                                        uint16_t aCallState,
                                        const nsAString& aNumber,
+                                       uint16_t aNumberPresentation,
+                                       const nsAString& aName,
+                                       uint16_t aNamePresentation,
                                        bool aIsOutgoing,
                                        bool aIsEmergency,
                                        bool aIsConference,
                                        bool aIsSwitchable,
                                        bool aIsMergeable)
 {
   for (uint32_t i = 0; i < mListeners.Length(); i++) {
     mListeners[i]->CallStateChanged(aClientId, aCallIndex, aCallState, aNumber,
+                                    aNumberPresentation, aName, aNamePresentation,
                                     aIsOutgoing, aIsEmergency, aIsConference,
                                     aIsSwitchable, aIsMergeable);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyIPCService::ConferenceCallStateChanged(uint16_t aCallState)
@@ -384,31 +388,38 @@ TelephonyIPCService::EnumerateCallStateC
   MOZ_CRASH("Not a EnumerateCalls request!");
 }
 
 NS_IMETHODIMP
 TelephonyIPCService::EnumerateCallState(uint32_t aClientId,
                                          uint32_t aCallIndex,
                                          uint16_t aCallState,
                                          const nsAString& aNumber,
+                                         uint16_t aNumberPresentation,
+                                         const nsAString& aName,
+                                         uint16_t aNamePresentation,
                                          bool aIsOutgoing,
                                          bool aIsEmergency,
                                          bool aIsConference,
                                          bool aIsSwitchable,
                                          bool aIsMergeable)
 {
   MOZ_CRASH("Not a EnumerateCalls request!");
 }
 
 NS_IMETHODIMP
 TelephonyIPCService::NotifyCdmaCallWaiting(uint32_t aClientId,
-                                            const nsAString& aNumber)
+                                            const nsAString& aNumber,
+                                            uint16_t aNumberPresentation,
+                                            const nsAString& aName,
+                                            uint16_t aNamePresentation)
 {
   for (uint32_t i = 0; i < mListeners.Length(); i++) {
-    mListeners[i]->NotifyCdmaCallWaiting(aClientId, aNumber);
+    mListeners[i]->NotifyCdmaCallWaiting(aClientId, aNumber, aNumberPresentation,
+                                         aName, aNamePresentation);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyIPCService::NotifyConferenceError(const nsAString& aName,
                                             const nsAString& aMessage)
 {
--- a/dom/telephony/ipc/TelephonyParent.cpp
+++ b/dom/telephony/ipc/TelephonyParent.cpp
@@ -278,25 +278,29 @@ TelephonyParent::RecvSetSpeakerEnabled(c
 
 // nsITelephonyListener
 
 NS_IMETHODIMP
 TelephonyParent::CallStateChanged(uint32_t aClientId,
                                   uint32_t aCallIndex,
                                   uint16_t aCallState,
                                   const nsAString& aNumber,
+                                  uint16_t aNumberPresentation,
+                                  const nsAString& aName,
+                                  uint16_t aNamePresentation,
                                   bool aIsOutgoing,
                                   bool aIsEmergency,
                                   bool aIsConference,
                                   bool aIsSwitchable,
                                   bool aIsMergeable)
 {
   NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
 
   IPCCallStateData data(aCallIndex, aCallState, nsString(aNumber),
+                        aNumberPresentation, nsString(aName), aNamePresentation,
                         aIsOutgoing, aIsEmergency, aIsConference,
                         aIsSwitchable, aIsMergeable);
   return SendNotifyCallStateChanged(aClientId, data) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 TelephonyParent::ConferenceCallStateChanged(uint16_t aCallState)
 {
@@ -312,33 +316,40 @@ TelephonyParent::EnumerateCallStateCompl
   MOZ_CRASH("Not a EnumerateCalls request!");
 }
 
 NS_IMETHODIMP
 TelephonyParent::EnumerateCallState(uint32_t aClientId,
                                     uint32_t aCallIndex,
                                     uint16_t aCallState,
                                     const nsAString& aNumber,
+                                    uint16_t aNumberPresentation,
+                                    const nsAString& aName,
+                                    uint16_t aNamePresentation,
                                     bool aIsOutgoing,
                                     bool aIsEmergency,
                                     bool aIsConference,
                                     bool aIsSwitchable,
                                     bool aIsMergeable)
 {
   MOZ_CRASH("Not a EnumerateCalls request!");
 }
 
 NS_IMETHODIMP
 TelephonyParent::NotifyCdmaCallWaiting(uint32_t aClientId,
-                                       const nsAString& aNumber)
+                                       const nsAString& aNumber,
+                                       uint16_t aNumberPresentation,
+                                       const nsAString& aName,
+                                       uint16_t aNamePresentation)
 {
   NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
 
-  return SendNotifyCdmaCallWaiting(aClientId, nsString(aNumber))
-      ? NS_OK : NS_ERROR_FAILURE;
+  IPCCdmaWaitingCallData data(nsString(aNumber), aNumberPresentation,
+                              nsString(aName), aNamePresentation);
+  return SendNotifyCdmaCallWaiting(aClientId, data) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 TelephonyParent::NotifyConferenceError(const nsAString& aName,
                                        const nsAString& aMessage)
 {
   NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
 
@@ -425,16 +436,19 @@ TelephonyRequestParent::DoRequest(const 
 
 // nsITelephonyListener
 
 NS_IMETHODIMP
 TelephonyRequestParent::CallStateChanged(uint32_t aClientId,
                                          uint32_t aCallIndex,
                                          uint16_t aCallState,
                                          const nsAString& aNumber,
+                                         uint16_t aNumberPresentation,
+                                         const nsAString& aName,
+                                         uint16_t aNamePresentation,
                                          bool aIsOutgoing,
                                          bool aIsEmergency,
                                          bool aIsConference,
                                          bool aIsSwitchable,
                                          bool aIsMergeable)
 {
   MOZ_CRASH("Not a TelephonyParent!");
 }
@@ -453,34 +467,41 @@ TelephonyRequestParent::EnumerateCallSta
   return Send__delete__(this, EnumerateCallsResponse()) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 TelephonyRequestParent::EnumerateCallState(uint32_t aClientId,
                                            uint32_t aCallIndex,
                                            uint16_t aCallState,
                                            const nsAString& aNumber,
+                                           uint16_t aNumberPresentation,
+                                           const nsAString& aName,
+                                           uint16_t aNamePresentation,
                                            bool aIsOutgoing,
                                            bool aIsEmergency,
                                            bool aIsConference,
                                            bool aIsSwitchable,
                                            bool aIsMergeable)
 {
   NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
 
   IPCCallStateData data(aCallIndex, aCallState, nsString(aNumber),
+                        aNumberPresentation, nsString(aName), aNamePresentation,
                         aIsOutgoing, aIsEmergency, aIsConference,
                         aIsSwitchable, aIsMergeable);
   return SendNotifyEnumerateCallState(aClientId, data) ? NS_OK
                                                        : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 TelephonyRequestParent::NotifyCdmaCallWaiting(uint32_t aClientId,
-                                              const nsAString& aNumber)
+                                              const nsAString& aNumber,
+                                              uint16_t aNumberPresentation,
+                                              const nsAString& aName,
+                                              uint16_t aNamePresentation)
 {
   MOZ_CRASH("Not a TelephonyParent!");
 }
 
 NS_IMETHODIMP
 TelephonyRequestParent::NotifyConferenceError(const nsAString& aName,
                                               const nsAString& aMessage)
 {
--- a/dom/telephony/ipc/TelephonyTypes.ipdlh
+++ b/dom/telephony/ipc/TelephonyTypes.ipdlh
@@ -8,18 +8,29 @@ namespace mozilla {
 namespace dom {
 namespace telephony {
 
 struct IPCCallStateData
 {
   uint32_t callIndex;
   uint16_t callState;
   nsString number;
+  uint16_t numberPresentation;
+  nsString name;
+  uint16_t namePresentation;
   bool     isOutGoing;
   bool     isEmergency;
   bool     isConference;
   bool     isSwitchable;
   bool     isMergeable;
 };
 
+struct IPCCdmaWaitingCallData
+{
+  nsString number;
+  uint16_t numberPresentation;
+  nsString name;
+  uint16_t namePresentation;
+};
+
 } /* namespace telephony */
 } /* namespace dom */
 } /* namespace mozilla */
--- a/dom/telephony/moz.build
+++ b/dom/telephony/moz.build
@@ -10,16 +10,17 @@ XPIDL_SOURCES += [
 
 XPIDL_MODULE = 'dom_telephony'
 
 EXPORTS.mozilla.dom += [
     'CallsList.h',
     'Telephony.h',
     'TelephonyCall.h',
     'TelephonyCallGroup.h',
+    'TelephonyCallId.h',
 ]
 
 EXPORTS.mozilla.dom.telephony += [
     'ipc/TelephonyChild.h',
     'ipc/TelephonyParent.h',
     'TelephonyCommon.h',
     'TelephonyFactory.h',
 ]
@@ -27,16 +28,17 @@ EXPORTS.mozilla.dom.telephony += [
 UNIFIED_SOURCES += [
     'CallsList.cpp',
     'ipc/TelephonyChild.cpp',
     'ipc/TelephonyIPCService.cpp',
     'ipc/TelephonyParent.cpp',
     'Telephony.cpp',
     'TelephonyCall.cpp',
     'TelephonyCallGroup.cpp',
+    'TelephonyCallId.cpp',
     'TelephonyFactory.cpp',
 ]
 
 IPDL_SOURCES += [
     'ipc/PTelephony.ipdl',
     'ipc/PTelephonyRequest.ipdl',
     'ipc/TelephonyTypes.ipdlh'
 ]
--- a/dom/telephony/nsIGonkTelephonyService.idl
+++ b/dom/telephony/nsIGonkTelephonyService.idl
@@ -5,25 +5,25 @@
 
 #include "nsITelephonyService.idl"
 
 %{C++
 #define GONK_TELEPHONY_SERVICE_CONTRACTID \
         "@mozilla.org/telephony/gonktelephonyservice;1"
 %}
 
-[scriptable, uuid(2ff3dcbb-ae63-443e-9c5d-76811f2f9b42)]
+[scriptable, uuid(8790e2cc-2c68-4ce9-90dc-f68e1b6e4886)]
 interface nsIGonkTelephonyService : nsITelephonyService
 {
   void notifyCallDisconnected(in unsigned long clientId, in jsval call);
 
   void notifyCallRing();
 
   void notifyCallStateChanged(in unsigned long clientId, in jsval call,
                               [optional] in boolean skipStateConversion);
 
-  void notifyCdmaCallWaiting(in unsigned long clientId, in AString number);
+  void notifyCdmaCallWaiting(in unsigned long clientId, in jsval waitingCall);
 
   void notifySupplementaryService(in unsigned long clientId, in long callIndex,
                                   in AString notification);
 
   void notifyConferenceCallStateChanged(in short state);
 };
--- a/dom/telephony/nsITelephonyService.idl
+++ b/dom/telephony/nsITelephonyService.idl
@@ -1,28 +1,36 @@
 /* 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/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(cd83030f-31eb-40c0-8f0e-0edef3527eec)]
+[scriptable, uuid(464d4cf8-454a-4cdb-9329-bfe7ede97103)]
 interface nsITelephonyListener : nsISupports
 {
   /**
    * Notified when a telephony call changes state.
    *
    * @param clientId
             Indicate the RIL client, 0 ~ (number of client - 1).
    * @param callIndex
    *        Call identifier assigned by the RIL.
    * @param callState
    *        One of the nsITelephonyService::CALL_STATE_* values.
    * @param number
    *        Number of the other party.
+   * @param numberPresentation
+   *        Presentation of the call number.
+   *        One of the nsITelephonyProvider::CALL_PRESENTATION_* values.
+   * @param name
+   *        Name of the other party.
+   * @param namePresentation
+   *        Presentation of the call name.
+   *        One of the nsITelephonyProvider::CALL_PRESENTATION_* values.
    * @param isOutgoing
    *        Indicates whether this call is outgoing or incoming.
    * @param isEmergency
    *        Indicates whether this call is an emergency call.
    * @param isConference
    *        Indicates whether this call is a conference call.
    * @param isSwitchable
    *        Indicates whether this call can be switched between states of
@@ -30,16 +38,19 @@ interface nsITelephonyListener : nsISupp
    *        nsITelephonyService::CALL_STATE_HELD.
    * @param isMergeable
    *        Indicates whether this call be be added into a conference.
    */
   void callStateChanged(in unsigned long clientId,
                         in unsigned long callIndex,
                         in unsigned short callState,
                         in AString number,
+                        in unsigned short numberPresentation,
+                        in AString name,
+                        in unsigned short namePresentation,
                         in boolean isOutgoing,
                         in boolean isEmergency,
                         in boolean isConference,
                         in boolean isSwitchable,
                         in boolean isMergeable);
 
   /**
    * Called when participants of a conference call have been updated, and the
@@ -66,31 +77,42 @@ interface nsITelephonyListener : nsISupp
    * @param clientId
             Indicate the RIL client, 0 ~ (number of client - 1).
    * @param callIndex
    *        Call identifier assigned by the RIL.
    * @param callState
    *        One of the nsITelephonyService::CALL_STATE_* values.
    * @param number
    *        Number of the other party.
+   * @param numberPresentation
+   *        Presentation of the call number.
+   *        One of the nsITelephonyProvider::CALL_PRESENTATION_* values.
+   * @param name
+   *        Name of the other party.
+   * @param namePresentation
+   *        Presentation of the call name.
+   *        One of the nsITelephonyProvider::CALL_PRESENTATION_* values.
    * @param isOutgoing
    *        Indicates whether this call is outgoing or incoming.
    * @param isConference
    *        Indicates whether this call is a conference call.
    * @param isSwitchable
    *        Indicates whether this call can be switched between states of
    *        nsITelephonyService::CALL_STATE_CONNECTED and
    *        nsITelephonyService::CALL_STATE_HELD.
    * @param isMergeable
    *        Indicates whether this call be be added into a conference.
    */
   void enumerateCallState(in unsigned long clientId,
                           in unsigned long callIndex,
                           in unsigned short callState,
                           in AString number,
+                          in unsigned short numberPresentation,
+                          in AString name,
+                          in unsigned short namePresentation,
                           in boolean isOutgoing,
                           in boolean isEmergency,
                           in boolean isConference,
                           in boolean isSwitchable,
                           in boolean isMergeable);
 
   /**
    * Notify when RIL receives supplementary service notification.
@@ -122,18 +144,30 @@ interface nsITelephonyListener : nsISupp
 
   /**
    * Called when a waiting call comes in CDMA networks.
    *
    * @param clientId
             Indicate the RIL client, 0 ~ (number of client - 1).
    * @param number
    *        Number of the other party.
+   * @param numberPresentation
+   *        Presentation of the call number.
+   *        One of the nsITelephonyProvider::CALL_PRESENTATION_* values.
+   * @param name
+   *        Name of the other party.
+   * @param namePresentation
+   *        Presentation of the call name.
+   *        One of the nsITelephonyProvider::CALL_PRESENTATION_* values.
    */
-  void notifyCdmaCallWaiting(in unsigned long clientId, in AString number);
+  void notifyCdmaCallWaiting(in unsigned long clientId,
+                             in AString number,
+                             in unsigned short numberPresentation,
+                             in AString name,
+                             in unsigned short namePresentation);
 
   /**
    * Called when RIL error occurs to creating or separating a conference call.
    *
    * @param name
    *        Error name. Possible values are addError and removeError.
    * @param message
    *        Detailed error message from RIL.
@@ -182,16 +216,21 @@ interface nsITelephonyService : nsISuppo
   const unsigned short CALL_STATE_RESUMING = 7;
   const unsigned short CALL_STATE_DISCONNECTING = 8;
   const unsigned short CALL_STATE_DISCONNECTED = 9;
   const unsigned short CALL_STATE_INCOMING = 10;
 
   const unsigned short NOTIFICATION_REMOTE_HELD = 0;
   const unsigned short NOTIFICATION_REMOTE_RESUMED = 1;
 
+  const unsigned short CALL_PRESENTATION_ALLOWED = 0;
+  const unsigned short CALL_PRESENTATION_RESTRICTED = 1;
+  const unsigned short CALL_PRESENTATION_UNKNOWN = 2;
+  const unsigned short CALL_PRESENTATION_PAYPHONE = 3;
+
   readonly attribute unsigned long defaultServiceId;
 
   /**
    * Called when a content process registers receiving unsolicited messages from
    * RadioInterfaceLayer in the chrome process. Only a content process that has
    * the 'telephony' permission is allowed to register.
    */
   void registerListener(in nsITelephonyListener listener);
--- a/dom/telephony/test/marionette/head.js
+++ b/dom/telephony/test/marionette/head.js
@@ -284,16 +284,48 @@ let emulator = (function() {
         }
         is(call.state, state);
         callback();
       };
     };
   }
 
   /**
+   * Convenient helper to check the expected call number and name.
+   *
+   * @param number
+   *        A string sent to modem.
+   * @param numberPresentation
+   *        An unsigned short integer sent to modem.
+   * @param name
+   *        A string sent to modem.
+   * @param namePresentation
+   *        An unsigned short integer sent to modem.
+   * @param receivedNumber
+   *        A string exposed by Telephony API.
+   * @param receivedName
+   *        A string exposed by Telephony API.
+   */
+  function checkCallId(number, numberPresentation, name, namePresentation,
+                       receivedNumber, receivedName) {
+    let expectedNum = !numberPresentation ? number : "";
+    is(receivedNumber, expectedNum, "check number per numberPresentation");
+
+    let expectedName;
+    if (numberPresentation) {
+      expectedName = "";
+    } else if (!namePresentation) {
+      expectedName = name ? name : "";
+    } else {
+      expectedName = "";
+    }
+    is(receivedName, expectedName, "check name per number/namePresentation");
+  }
+
+  /**
    * Convenient helper to check the call list existing in the emulator.
    *
    * @param expectedCallList
    *        An array of call info with the format of "callStrPool()[state]".
    * @return A deferred promise.
    */
   function checkEmulatorCallList(expectedCallList) {
     let deferred = Promise.defer();
@@ -389,17 +421,17 @@ let emulator = (function() {
   function dial(number, serviceId) {
     serviceId = typeof serviceId !== "undefined" ? serviceId : 0;
     log("Make an outgoing call: " + number + ", serviceId: " + serviceId);
 
     let deferred = Promise.defer();
 
     telephony.dial(number, serviceId).then(call => {
       ok(call);
-      is(call.number, number);
+      is(call.id.number, number);
       is(call.state, "dialing");
       is(call.serviceId, serviceId);
 
       call.onalerting = function onalerting(event) {
         call.onalerting = null;
         log("Received 'onalerting' call event.");
         checkEventCallState(event, call, "alerting");
         deferred.resolve(call);
@@ -493,41 +525,72 @@ let emulator = (function() {
       deferred.resolve(call);
     };
     call.hold();
 
     return deferred.promise;
   }
 
   /**
+   * Locally hang up a call.
+   *
+   * @param call
+   *        A TelephonyCall object.
+   * @return A deferred promise.
+   */
+  function hangUp(call) {
+    let deferred = Promise.defer();
+
+    call.ondisconnected = function(event) {
+      log("Received 'disconnected' call event");
+      call.ondisconnected = null;
+      checkEventCallState(event, call, "disconnected");
+      deferred.resolve(call);
+    };
+    call.hangUp();
+
+    return deferred.promise;
+  }
+
+  /**
    * Simulate an incoming call.
    *
    * @param number
    *        A string.
+   * @param numberPresentation [optional]
+   *        An unsigned short integer.
+   * @param name [optional]
+   *        A string.
+   * @param namePresentation [optional]
+   *        An unsigned short integer.
    * @return A deferred promise.
    */
-  function remoteDial(number) {
+  function remoteDial(number, numberPresentation, name, namePresentation) {
     log("Simulating an incoming call.");
 
     let deferred = Promise.defer();
 
     telephony.onincoming = function onincoming(event) {
       log("Received 'incoming' call event.");
       telephony.onincoming = null;
 
       let call = event.call;
 
       ok(call);
-      is(call.number, number);
       is(call.state, "incoming");
-
+      checkCallId(number, numberPresentation, name, namePresentation,
+                  call.id.number, call.id.name);
       deferred.resolve(call);
     };
-    emulator.run("gsm call " + number);
 
+    numberPresentation = numberPresentation || "";
+    name = name || "";
+    namePresentation = namePresentation || "";
+    emulator.run("gsm call " + number + "," + numberPresentation + "," + name +
+                 "," + namePresentation);
     return deferred.promise;
   }
 
   /**
    * Remote party answers the call.
    *
    * @param call
    *        A TelephonyCall object.
@@ -539,17 +602,17 @@ let emulator = (function() {
     let deferred = Promise.defer();
 
     call.onconnected = function onconnected(event) {
       log("Received 'connected' call event.");
       call.onconnected = null;
       checkEventCallState(event, call, "connected");
       deferred.resolve(call);
     };
-    emulator.run("gsm accept " + call.number);
+    emulator.run("gsm accept " + call.id.number);
 
     return deferred.promise;
   }
 
   /**
    * Remote party hangs up the call.
    *
    * @param call
@@ -562,17 +625,17 @@ let emulator = (function() {
     let deferred = Promise.defer();
 
     call.ondisconnected = function ondisconnected(event) {
       log("Received 'disconnected' call event.");
       call.ondisconnected = null;
       checkEventCallState(event, call, "disconnected");
       deferred.resolve(call);
     };
-    emulator.run("gsm cancel " + call.number);
+    emulator.run("gsm cancel " + call.id.number);
 
     return deferred.promise;
   }
 
   /**
    * Remote party hangs up all the calls.
    *
    * @param calls
@@ -611,17 +674,17 @@ let emulator = (function() {
     let pending = ["conference.oncallschanged", "conference.onconnected"];
     let receive = function(name) {
       receivedPending(name, pending, done);
     };
 
     let check_onconnected  = StateEventChecker('connected', 'onresuming');
 
     for (let call of callsToAdd) {
-      let callName = "callToAdd (" + call.number + ')';
+      let callName = "callToAdd (" + call.id.number + ')';
 
       let ongroupchange = callName + ".ongroupchange";
       pending.push(ongroupchange);
       check_ongroupchange(call, callName, conference,
                           receive.bind(null, ongroupchange));
 
       let onstatechange = callName + ".onstatechange";
       pending.push(onstatechange);
@@ -672,17 +735,17 @@ let emulator = (function() {
     let receive = function(name) {
       receivedPending(name, pending, done);
     };
 
     let check_onholding = StateEventChecker('holding', null);
     let check_onheld = StateEventChecker('held', 'onholding');
 
     for (let call of calls) {
-      let callName = "call (" + call.number + ')';
+      let callName = "call (" + call.id.number + ')';
 
       let onholding = callName + ".onholding";
       pending.push(onholding);
       check_onholding(call, callName, receive.bind(null, onholding));
 
       let onheld = callName + ".onheld";
       pending.push(onheld);
       check_onheld(call, callName, receive.bind(null, onheld));
@@ -725,17 +788,17 @@ let emulator = (function() {
     let receive = function(name) {
       receivedPending(name, pending, done);
     };
 
     let check_onresuming   = StateEventChecker('resuming', null);
     let check_onconnected  = StateEventChecker('connected', 'onresuming');
 
     for (let call of calls) {
-      let callName = "call (" + call.number + ')';
+      let callName = "call (" + call.id.number + ')';
 
       let onresuming = callName + ".onresuming";
       pending.push(onresuming);
       check_onresuming(call, callName, receive.bind(null, onresuming));
 
       let onconnected = callName + ".onconnected";
       pending.push(onconnected);
       check_onconnected(call, callName, receive.bind(null, onconnected));
@@ -784,28 +847,28 @@ let emulator = (function() {
     let pending = ["callToRemove.ongroupchange", "telephony.oncallschanged",
                    "conference.oncallschanged", "conference.onstatechange"];
     let receive = function(name) {
       receivedPending(name, pending, done);
     };
 
     // Remained call in conference will be held.
     for (let call of remainedCalls) {
-      let callName = "remainedCall (" + call.number + ')';
+      let callName = "remainedCall (" + call.id.number + ')';
 
       let onstatechange = callName + ".onstatechange";
       pending.push(onstatechange);
       check_onstatechange(call, callName, 'held',
                           receive.bind(null, onstatechange));
     }
 
     // When a call is removed from conference with 2 calls, another one will be
     // automatically removed from group and be put on hold.
     for (let call of autoRemovedCalls) {
-      let callName = "autoRemovedCall (" + call.number + ')';
+      let callName = "autoRemovedCall (" + call.id.number + ')';
 
       let ongroupchange = callName + ".ongroupchange";
       pending.push(ongroupchange);
       check_ongroupchange(call, callName, null,
                           receive.bind(null, ongroupchange));
 
       let onstatechange = callName + ".onstatechange";
       pending.push(onstatechange);
@@ -868,17 +931,17 @@ let emulator = (function() {
     let pending = ["conference.oncallschanged", "remoteHangUp"];
     let receive = function(name) {
       receivedPending(name, pending, done);
     };
 
     // When a call is hang up from conference with 2 calls, another one will be
     // automatically removed from group.
     for (let call of autoRemovedCalls) {
-      let callName = "autoRemovedCall (" + call.number + ')';
+      let callName = "autoRemovedCall (" + call.id.number + ')';
 
       let ongroupchange = callName + ".ongroupchange";
       pending.push(ongroupchange);
       check_ongroupchange(call, callName, null,
                           receive.bind(null, ongroupchange));
     }
 
     if (autoRemovedCalls.length) {
@@ -957,18 +1020,18 @@ let emulator = (function() {
    *        Number of an incoming call.
    * @param conferenceCalls
    *        Calls already in conference.
    * @return Promise<[calls in the conference]>
    */
   function createCallAndAddToConference(inNumber, conferenceCalls) {
     // Create an info array. allInfo = [info1, info2, ...].
     let allInfo = conferenceCalls.map(function(call, i) {
-      return (i === 0) ? outCallStrPool(call.number)
-                       : inCallStrPool(call.number);
+      return (i === 0) ? outCallStrPool(call.id.number)
+                       : inCallStrPool(call.id.number);
     });
 
     // Define state property of the info array.
     // Ex: allInfo.active = [info1.active, info2.active, ...].
     function addInfoState(allInfo, state) {
       Object.defineProperty(allInfo, state, {
         get: function() {
           return allInfo.map(function(info) { return info[state]; });
@@ -1037,16 +1100,17 @@ let emulator = (function() {
   this.gCheckInitialState = checkInitialState;
   this.gClearCalls = clearCalls;
   this.gOutCallStrPool = outCallStrPool;
   this.gInCallStrPool = inCallStrPool;
   this.gCheckState = checkState;
   this.gCheckAll = checkAll;
   this.gDial = dial;
   this.gAnswer = answer;
+  this.gHangUp = hangUp;
   this.gHold = hold;
   this.gRemoteDial = remoteDial;
   this.gRemoteAnswer = remoteAnswer;
   this.gRemoteHangUp = remoteHangUp;
   this.gRemoteHangUpCalls = remoteHangUpCalls;
   this.gAddCallsToConference = addCallsToConference;
   this.gHoldConference = holdConference;
   this.gResumeConference = resumeConference;
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -52,8 +52,9 @@ disabled = Bug 821958
 [test_conference_add_error.js]
 [test_conference_remove_error.js]
 [test_conference_two_hangup_one.js]
 [test_conference_two_hold_resume.js]
 [test_conference_two_remove_one.js]
 [test_conference_three_hangup_one.js]
 [test_conference_three_remove_one.js]
 [test_outgoing_when_two_calls_on_line.js]
+[test_call_presentation.js]
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_call_presentation.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+const ALLOWED = 0;
+const RESTRICTED = 1;
+const UNKNOWN = 2;
+const PAYPHONE =3;
+
+function getPresentationStr(presentation) {
+  let str;
+  switch (presentation) {
+    case ALLOWED:
+      str = "allowed";
+      break;
+    case RESTRICTED:
+      str = "restricted";
+      break;
+    case UNKNOWN:
+      str = "unknown";
+      break;
+    case PAYPHONE:
+      str = "payphone";
+      break;
+  }
+  return str;
+}
+
+function getNamePresentation(numberPresentation, namePresentation) {
+  // See TS 23.096 Figure 3a and Annex A Note 1.
+  if (!numberPresentation) {
+    if (namePresentation == undefined) {
+      namePresentation = ALLOWED;
+    }
+  } else {
+    namePresentation = ALLOWED;
+  }
+  return getPresentationStr(namePresentation);
+}
+
+function test(number, numberPresentation, name, namePresentation) {
+  return gRemoteDial(number, numberPresentation, name, namePresentation)
+    .then(call => {
+      is(call.id.numberPresentation, getPresentationStr(numberPresentation),
+         "check numberPresentation");
+      is(call.id.namePresentation,
+         getNamePresentation(numberPresentation, namePresentation),
+         "check namePresentation");
+      return call;
+    })
+    .then(gHangUp);
+}
+
+startTest(function() {
+  let inNumber = "5555550201";
+  Promise.resolve()
+    .then(() => test(inNumber, ALLOWED))
+    .then(() => test(inNumber, RESTRICTED))
+    .then(() => test(inNumber, UNKNOWN))
+    .then(() => test(inNumber, PAYPHONE))
+    .then(() => test(inNumber, ALLOWED, "TestName"))
+    .then(() => test(inNumber, ALLOWED, "TestName", ALLOWED))
+    .then(() => test(inNumber, ALLOWED, "TestName", RESTRICTED))
+    .then(() => test(inNumber, ALLOWED, "TestName", UNKNOWN))
+    .then(() => test(inNumber, RESTRICTED, "TestName", ALLOWED))
+    .then(() => test(inNumber, RESTRICTED, "TestName", RESTRICTED))
+    .then(() => test(inNumber, RESTRICTED, "TestName", UNKNOWN))
+    .then(finish);
+});
--- a/dom/telephony/test/marionette/test_emergency.js
+++ b/dom/telephony/test/marionette/test_emergency.js
@@ -9,17 +9,17 @@ let outgoing;
 let calls;
 
 function dial() {
   log("Make an emergency call.");
 
   telephony.dialEmergency(number).then(call => {
     outgoing = call;
     ok(outgoing);
-    is(outgoing.number, number);
+    is(outgoing.id.number, number);
     is(outgoing.state, "dialing");
 
     is(outgoing, telephony.active);
     //ok(telephony.calls === calls); // bug 717414
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoing);
 
     outgoing.onalerting = function onalerting(event) {
--- a/dom/telephony/test/marionette/test_incoming_already_connected.js
+++ b/dom/telephony/test/marionette/test_incoming_already_connected.js
@@ -10,17 +10,17 @@ let outgoingCall;
 let incomingCall;
 let gotOriginalConnected = false;
 
 function dial() {
   log("Make an outgoing call.");
   telephony.dial(outNumber).then(call => {
     outgoingCall = call;
     ok(outgoingCall);
-    is(outgoingCall.number, outNumber);
+    is(outgoingCall.id.number, outNumber);
     is(outgoingCall.state, "dialing");
 
     is(outgoingCall, telephony.active);
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoingCall);
 
     outgoingCall.onalerting = function onalerting(event) {
       log("Received 'onalerting' call event.");
@@ -69,17 +69,17 @@ function answer() {
 // With one connected call already, simulate an incoming call
 function simulateIncoming() {
   log("Simulating an incoming call (with one call already connected).");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     // Should be two calls now
     is(telephony.calls.length, 2);
     is(telephony.calls[0], outgoingCall);
     is(telephony.calls[1], incomingCall);
 
     emulator.run("gsm list", function(result) {
--- a/dom/telephony/test/marionette/test_incoming_already_held.js
+++ b/dom/telephony/test/marionette/test_incoming_already_held.js
@@ -10,17 +10,17 @@ let outgoingCall;
 let incomingCall;
 let gotOriginalConnected = false;
 
 function dial() {
   log("Make an outgoing call.");
   telephony.dial(outNumber).then(call => {
     outgoingCall = call;
     ok(outgoingCall);
-    is(outgoingCall.number, outNumber);
+    is(outgoingCall.id.number, outNumber);
     is(outgoingCall.state, "dialing");
 
     is(outgoingCall, telephony.active);
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoingCall);
 
     outgoingCall.onalerting = function onalerting(event) {
       log("Received 'onalerting' call event.");
@@ -100,17 +100,17 @@ function holdCall() {
 // With one call on hold, simulate an incoming call
 function simulateIncoming() {
   log("Simulating an incoming call (with one call already held).");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     // Should be two calls now
     is(telephony.calls.length, 2);
     is(telephony.calls[0], outgoingCall);
     is(telephony.calls[1], incomingCall);
 
     emulator.run("gsm list", function(result) {
--- a/dom/telephony/test/marionette/test_incoming_answer_hangup.js
+++ b/dom/telephony/test/marionette/test_incoming_answer_hangup.js
@@ -10,17 +10,17 @@ let calls;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incoming = event.call;
     ok(incoming);
-    is(incoming.number, number);
+    is(incoming.id.number, number);
     is(incoming.state, "incoming");
 
     //ok(telephony.calls === calls); // bug 717414
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incoming);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
--- a/dom/telephony/test/marionette/test_incoming_answer_hangup_oncallschanged.js
+++ b/dom/telephony/test/marionette/test_incoming_answer_hangup_oncallschanged.js
@@ -17,17 +17,17 @@ function simulateIncoming() {
       log("Notifying calls array is loaded. No call information accompanies.");
       return;
     }
 
     telephony.oncallschanged = null;
 
     incoming = event.call;
     ok(incoming);
-    is(incoming.number, number);
+    is(incoming.id.number, number);
     is(incoming.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incoming);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + number + " : incoming");
--- a/dom/telephony/test/marionette/test_incoming_answer_remote_hangup.js
+++ b/dom/telephony/test/marionette/test_incoming_answer_remote_hangup.js
@@ -9,17 +9,17 @@ let incomingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + inNumber + " : incoming");
--- a/dom/telephony/test/marionette/test_incoming_connecting_hangup.js
+++ b/dom/telephony/test/marionette/test_incoming_connecting_hangup.js
@@ -9,17 +9,17 @@ let incomingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + inNumber + " : incoming");
--- a/dom/telephony/test/marionette/test_incoming_connecting_remote_hangup.js
+++ b/dom/telephony/test/marionette/test_incoming_connecting_remote_hangup.js
@@ -9,17 +9,17 @@ let incomingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + inNumber + " : incoming");
--- a/dom/telephony/test/marionette/test_incoming_hangup_held.js
+++ b/dom/telephony/test/marionette/test_incoming_hangup_held.js
@@ -9,17 +9,17 @@ let incomingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + inNumber + " : incoming");
--- a/dom/telephony/test/marionette/test_incoming_hold_resume.js
+++ b/dom/telephony/test/marionette/test_incoming_hold_resume.js
@@ -10,17 +10,17 @@ let incomingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, number);
+    is(incomingCall.id.number, number);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + number + " : incoming");
--- a/dom/telephony/test/marionette/test_incoming_onstatechange.js
+++ b/dom/telephony/test/marionette/test_incoming_onstatechange.js
@@ -9,17 +9,17 @@ let inNumber = "5555551111";
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + inNumber + " : incoming");
--- a/dom/telephony/test/marionette/test_incoming_reject.js
+++ b/dom/telephony/test/marionette/test_incoming_reject.js
@@ -10,17 +10,17 @@ let calls;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incoming = event.call;
     ok(incoming);
-    is(incoming.number, number);
+    is(incoming.id.number, number);
     is(incoming.state, "incoming");
 
     //ok(telephony.calls === calls); // bug 717414
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incoming);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
--- a/dom/telephony/test/marionette/test_incoming_remote_cancel.js
+++ b/dom/telephony/test/marionette/test_incoming_remote_cancel.js
@@ -9,17 +9,17 @@ let incomingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + inNumber + " : incoming");
--- a/dom/telephony/test/marionette/test_incoming_remote_hangup_held.js
+++ b/dom/telephony/test/marionette/test_incoming_remote_hangup_held.js
@@ -9,17 +9,17 @@ let incomingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + inNumber + " : incoming");
--- a/dom/telephony/test/marionette/test_multiple_hold.js
+++ b/dom/telephony/test/marionette/test_multiple_hold.js
@@ -11,17 +11,17 @@ let outgoingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + inNumber + " : incoming");
@@ -94,17 +94,17 @@ function holdCall() {
 
 // With one call on hold, make outgoing call
 function dial() {
   log("Making an outgoing call (while have one call already held).");
 
   telephony.dial(outNumber).then(call => {
     outgoingCall = call;
     ok(outgoingCall);
-    is(outgoingCall.number, outNumber);
+    is(outgoingCall.id.number, outNumber);
     is(outgoingCall.state, "dialing");
     is(outgoingCall, telephony.active);
     is(telephony.calls.length, 2);
     is(telephony.calls[0], incomingCall);
     is(telephony.calls[1], outgoingCall);
 
     outgoingCall.onalerting = function onalerting(event) {
       log("Received 'onalerting' call event.");
--- a/dom/telephony/test/marionette/test_outgoing_already_held.js
+++ b/dom/telephony/test/marionette/test_outgoing_already_held.js
@@ -11,17 +11,17 @@ let outgoingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     // Wait for emulator to catch up before continuing
     waitFor(verifyCallList,function() {
       return(rcvdEmulatorCallback);
@@ -107,17 +107,17 @@ function holdCall(){
 
 // With one call on hold, make outgoing call
 function dial() {
   log("Making an outgoing call (while have one call already held).");
 
   telephony.dial(outNumber).then(call => {
     outgoingCall = call;
     ok(outgoingCall);
-    is(outgoingCall.number, outNumber);
+    is(outgoingCall.id.number, outNumber);
     is(outgoingCall.state, "dialing");
 
     is(outgoingCall, telephony.active);
     is(telephony.calls.length, 2);
     is(telephony.calls[0], incomingCall);
     is(telephony.calls[1], outgoingCall);
 
     outgoingCall.onalerting = function onalerting(event) {
--- a/dom/telephony/test/marionette/test_outgoing_answer_hangup.js
+++ b/dom/telephony/test/marionette/test_outgoing_answer_hangup.js
@@ -9,17 +9,17 @@ let outgoing;
 let calls;
 
 function dial() {
   log("Make an outgoing call.");
 
   telephony.dial(number).then(call => {
     outgoing = call;
     ok(outgoing);
-    is(outgoing.number, number);
+    is(outgoing.id.number, number);
     is(outgoing.state, "dialing");
 
     is(outgoing, telephony.active);
     //ok(telephony.calls === calls); // bug 717414
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoing);
 
     outgoing.onalerting = function onalerting(event) {
--- a/dom/telephony/test/marionette/test_outgoing_answer_hangup_oncallschanged.js
+++ b/dom/telephony/test/marionette/test_outgoing_answer_hangup_oncallschanged.js
@@ -20,17 +20,17 @@ function dial() {
 
     let expected_states = ["dialing", "disconnected"];
     ok(expected_states.indexOf(event.call.state) != -1,
       "Unexpected call state: " + event.call.state);
 
     if (event.call.state == "dialing") {
       outgoing = event.call;
       ok(outgoing);
-      is(outgoing.number, number);
+      is(outgoing.id.number, number);
 
       is(outgoing, telephony.active);
       is(telephony.calls.length, 1);
       is(telephony.calls[0], outgoing);
 
       checkCallList();
     }
 
--- a/dom/telephony/test/marionette/test_outgoing_answer_local_hangup.js
+++ b/dom/telephony/test/marionette/test_outgoing_answer_local_hangup.js
@@ -8,17 +8,17 @@ let outgoingCall;
 let outNumber = "5555551111";
 
 function dial() {
   log("Make an outgoing call.");
 
   telephony.dial(outNumber).then(call => {
     outgoingCall = call;
     ok(outgoingCall);
-    is(outgoingCall.number, outNumber);
+    is(outgoingCall.id.number, outNumber);
     is(outgoingCall.state, "dialing");
 
     is(outgoingCall, telephony.active);
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoingCall);
 
     outgoingCall.onalerting = function onalerting(event) {
       log("Received 'alerting' call event.");
--- a/dom/telephony/test/marionette/test_outgoing_answer_radio_off.js
+++ b/dom/telephony/test/marionette/test_outgoing_answer_radio_off.js
@@ -27,17 +27,17 @@ function setRadioEnabled(enabled) {
 }
 
 function dial(number) {
   log("Make an outgoing call.");
 
   let deferred = Promise.defer();
   telephony.dial(number).then(call => {
     ok(call);
-    is(call.number, number);
+    is(call.id.number, number);
     is(call.state, "dialing");
 
     call.onalerting = function(event) {
       log("Received 'onalerting' call event.");
       call.onalerting = null;
       is(call, event.call);
       is(call.state, "alerting");
       deferred.resolve(call);
@@ -54,17 +54,17 @@ function remoteAnswer(call) {
 
   call.onconnected = function(event) {
     log("Received 'connected' call event.");
     call.onconnected = null;
     is(call, event.call);
     is(call.state, "connected");
     deferred.resolve(call);
   };
-  emulator.run("gsm accept " + call.number);
+  emulator.run("gsm accept " + call.id.number);
 
   return deferred.promise;
 }
 
 function disableRadioAndWaitForCallEvent(call) {
   log("Disable radio and wait for call event.");
 
   let deferred = Promise.defer();
--- a/dom/telephony/test/marionette/test_outgoing_badNumber.js
+++ b/dom/telephony/test/marionette/test_outgoing_badNumber.js
@@ -12,17 +12,17 @@ function dial() {
   log("Make an outgoing call to an invalid number.");
 
   // Note: The number is valid from the view of phone and the call could be
   // dialed out successfully. However, it will later receive the BadNumberError
   // from network side.
   telephony.dial(number).then(call => {
     outgoing = call;
     ok(outgoing);
-    is(outgoing.number, number);
+    is(outgoing.id.number, number);
     is(outgoing.state, "dialing");
 
     is(outgoing, telephony.active);
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoing);
 
     outgoing.onerror = function onerror(event) {
       log("Received 'error' event.");
--- a/dom/telephony/test/marionette/test_outgoing_busy.js
+++ b/dom/telephony/test/marionette/test_outgoing_busy.js
@@ -8,17 +8,17 @@ let number = "5555552368";
 let outgoing;
 
 function dial() {
   log("Make an outgoing call.");
 
   telephony.dial(number).then(call => {
     outgoing = call;
     ok(outgoing);
-    is(outgoing.number, number);
+    is(outgoing.id.number, number);
     is(outgoing.state, "dialing");
 
     is(outgoing, telephony.active);
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoing);
 
     outgoing.onalerting = function onalerting(event) {
       log("Received 'onalerting' call event.");
--- a/dom/telephony/test/marionette/test_outgoing_hangup_alerting.js
+++ b/dom/telephony/test/marionette/test_outgoing_hangup_alerting.js
@@ -9,17 +9,17 @@ let outgoing;
 let calls;
 
 function dial() {
   log("Make an outgoing call.");
 
   telephony.dial(number).then(call => {
     outgoing = call;
     ok(outgoing);
-    is(outgoing.number, number);
+    is(outgoing.id.number, number);
     is(outgoing.state, "dialing");
 
     is(outgoing, telephony.active);
     //ok(telephony.calls === calls); // bug 717414
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoing);
 
     outgoing.onalerting = function onalerting(event) {
--- a/dom/telephony/test/marionette/test_outgoing_hangup_held.js
+++ b/dom/telephony/test/marionette/test_outgoing_hangup_held.js
@@ -9,17 +9,17 @@ let outgoing;
 let calls;
 
 function dial() {
   log("Make an outgoing call.");
 
   telephony.dial(number).then(call => {
     outgoing = call;
     ok(outgoing);
-    is(outgoing.number, number);
+    is(outgoing.id.number, number);
     is(outgoing.state, "dialing");
     is(outgoing, telephony.active);
     //ok(telephony.calls === calls); // bug 717414
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoing);
 
     outgoing.onalerting = function onalerting(event) {
       log("Received 'onalerting' call event.");
--- a/dom/telephony/test/marionette/test_outgoing_hold_resume.js
+++ b/dom/telephony/test/marionette/test_outgoing_hold_resume.js
@@ -9,17 +9,17 @@ let connectedCalls;
 let outgoingCall;
 
 function dial() {
   log("Make an outgoing call.");
 
   telephony.dial(number).then(call => {
     outgoingCall = call;
     ok(outgoingCall);
-    is(outgoingCall.number, number);
+    is(outgoingCall.id.number, number);
     is(outgoingCall.state, "dialing");
 
     is(outgoingCall, telephony.active);
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoingCall);
 
     outgoingCall.onalerting = function onalerting(event) {
       log("Received 'onalerting' call event.");
--- a/dom/telephony/test/marionette/test_outgoing_onstatechange.js
+++ b/dom/telephony/test/marionette/test_outgoing_onstatechange.js
@@ -8,17 +8,17 @@ let outgoingCall;
 let outNumber = "5555551111";
 
 function dial() {
   log("Make an outgoing call.");
 
   telephony.dial(outNumber).then(call => {
     outgoingCall = call;
     ok(outgoingCall);
-    is(outgoingCall.number, outNumber);
+    is(outgoingCall.id.number, outNumber);
     is(outgoingCall.state, "dialing");
 
     is(outgoingCall, telephony.active);
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoingCall);
 
     outgoingCall.onstatechange = function statechangering(event) {
       log("Received 'onstatechange' call event.");
--- a/dom/telephony/test/marionette/test_outgoing_reject.js
+++ b/dom/telephony/test/marionette/test_outgoing_reject.js
@@ -8,17 +8,17 @@ let number = "5555552368";
 let outgoing;
 
 function dial() {
   log("Make an outgoing call.");
 
   telephony.dial(number).then(call => {
     outgoing = call;
     ok(outgoing);
-    is(outgoing.number, number);
+    is(outgoing.id.number, number);
     is(outgoing.state, "dialing");
 
     is(outgoing, telephony.active);
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoing);
 
     outgoing.onalerting = function onalerting(event) {
       log("Received 'onalerting' call event.");
--- a/dom/telephony/test/marionette/test_outgoing_remote_hangup_held.js
+++ b/dom/telephony/test/marionette/test_outgoing_remote_hangup_held.js
@@ -7,17 +7,17 @@ let outNumber = "5555551111";
 let outgoingCall;
 
 function dial() {
   log("Make an outgoing call.");
 
   telephony.dial(outNumber).then(call => {
     outgoingCall = call;
     ok(outgoingCall);
-    is(outgoingCall.number, outNumber);
+    is(outgoingCall.id.number, outNumber);
     is(outgoingCall.state, "dialing");
 
     is(outgoingCall, telephony.active);
     is(telephony.calls.length, 1);
     is(telephony.calls[0], outgoingCall);
 
     outgoingCall.onalerting = function onalerting(event) {
       log("Received 'alerting' call event.");
--- a/dom/telephony/test/marionette/test_redundant_operations.js
+++ b/dom/telephony/test/marionette/test_redundant_operations.js
@@ -9,17 +9,17 @@ let incomingCall;
 
 function simulateIncoming() {
   log("Simulating an incoming call.");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     is(telephony.calls.length, 1);
     is(telephony.calls[0], incomingCall);
 
     emulator.run("gsm list", function(result) {
       log("Call list is now: " + result);
       is(result[0], "inbound from " + inNumber + " : incoming");
--- a/dom/telephony/test/marionette/test_swap_held_and_active.js
+++ b/dom/telephony/test/marionette/test_swap_held_and_active.js
@@ -12,17 +12,17 @@ let gotOriginalConnected = false;
 let gotHeld = false;
 let gotConnected = false;
 
 function dial() {
   log("Make an outgoing call.");
   telephony.dial(outNumber).then(call => {
     outgoingCall = call;
     ok(outgoingCall);
-    is(outgoingCall.number, outNumber);
+    is(outgoingCall.id.number, outNumber);
     is(outgoingCall.state, "dialing");
 
     outgoingCall.onalerting = function onalerting(event) {
       log("Received 'alerting' call event.");
 
       is(outgoingCall, event.call);
       is(outgoingCall.state, "alerting");
       is(outgoingCall, telephony.active);
@@ -102,17 +102,17 @@ function holdCall() {
 // With one call on hold, simulate an incoming call
 function simulateIncoming() {
   log("Simulating an incoming call (with one call already held).");
 
   telephony.onincoming = function onincoming(event) {
     log("Received 'incoming' call event.");
     incomingCall = event.call;
     ok(incomingCall);
-    is(incomingCall.number, inNumber);
+    is(incomingCall.id.number, inNumber);
     is(incomingCall.state, "incoming");
 
     // Should be two calls now
     is(telephony.calls.length, 2);
     is(telephony.calls[0], outgoingCall);
     is(telephony.calls[1], incomingCall);
 
     emulator.run("gsm list", function(result) {
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -1110,16 +1110,18 @@ var interfaceNamesInGlobalScope =
     "SVGZoomEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Telephony", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TelephonyCall", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TelephonyCallGroup", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "TelephonyCallId", b2g: true, pref: "dom.telephony.enabled"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "Text",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TextDecoder",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TextEncoder",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TextMetrics",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/MozMobileNetworkInfo.webidl
+++ b/dom/webidl/MozMobileNetworkInfo.webidl
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 enum MobileNetworkState {"available", "connected", "forbidden"};
 
 [Pref="dom.mobileconnection.enabled",
- ChromeConstructor(DOMString shortName, DOMString longName, DOMString mcc,
-                   DOMString mnc, DOMString state)]
+ ChromeConstructor(DOMString? shortName, DOMString? longName, DOMString? mcc,
+                   DOMString? mnc, DOMString? state)]
 interface MozMobileNetworkInfo
 {
   /**
    * Short name of the network operator.
    */
   readonly attribute DOMString? shortName;
 
   /**
--- a/dom/webidl/TelephonyCall.webidl
+++ b/dom/webidl/TelephonyCall.webidl
@@ -4,21 +4,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 [Pref="dom.telephony.enabled"]
 interface TelephonyCall : EventTarget {
   // Indicate which service the call comes from.
   readonly attribute unsigned long serviceId;
 
-  readonly attribute DOMString number;
+  readonly attribute TelephonyCallId id;
 
   // In CDMA networks, the 2nd waiting call shares the connection with the 1st
-  // call. We need an additional attribute for the 2nd number.
-  readonly attribute DOMString? secondNumber;
+  // call. We need an additional attribute for the CDMA waiting call.
+  readonly attribute TelephonyCallId? secondId;
 
   readonly attribute DOMString state;
 
   // The property "emergency" indicates whether the call number is an emergency
   // number. Only the outgoing call could have a value with true and it is
   // available after dialing state.
   readonly attribute boolean emergency;
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/TelephonyCallId.webidl
@@ -0,0 +1,35 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+enum CallIdPresentation {
+  "allowed",
+  // Call number/name has been withheld by the calling party.
+  "restricted",
+  // Call number is not available due to calling party being of type payphone.
+  "payphone",
+  // Call number/name is not available due to networking problems or other reason.
+  "unknown"
+};
+
+[Pref="dom.telephony.enabled"]
+interface TelephonyCallId {
+  // It is an empty string when "numberPresentation" is not "allowed."
+  readonly attribute DOMString number;
+
+  // This attribute is not relevant for outgoing calls. Default value is
+  // "allowed."
+  readonly attribute CallIdPresentation numberPresentation;
+
+  // This attribute is not relevant for outgoing calls. It is an empty string
+  // 1) when the call is outgoing, or 2) when the call is incoming and
+  // "namePresentation" is not "allowed." However, it could still be empty
+  // even the call is incoming and "namePresentation" is "allowed."
+  readonly attribute DOMString name;
+
+  // This attribute is not relevant for outgoing calls. Default value is
+  // "allowed."
+  readonly attribute CallIdPresentation namePresentation;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -432,16 +432,17 @@ WEBIDL_FILES = [
     'SVGURIReference.webidl',
     'SVGUseElement.webidl',
     'SVGViewElement.webidl',
     'SVGZoomAndPan.webidl',
     'SVGZoomEvent.webidl',
     'Telephony.webidl',
     'TelephonyCall.webidl',
     'TelephonyCallGroup.webidl',
+    'TelephonyCallId.webidl',
     'Text.webidl',
     'TextDecoder.webidl',
     'TextEncoder.webidl',
     'TextTrack.webidl',
     'TextTrackCueList.webidl',
     'TextTrackList.webidl',
     'TimeEvent.webidl',
     'TimeRanges.webidl',
--- a/mobile/android/base/AppConstants.java.in
+++ b/mobile/android/base/AppConstants.java.in
@@ -1,18 +1,16 @@
 #filter substitution
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko;
 
-import android.app.Activity;
-
 import org.mozilla.gecko.mozglue.RobocopTarget;
 
 /**
  * A collection of constants that pertain to the build and runtime state of the
  * application. Typically these are sourced from build-time definitions (see
  * Makefile.in). This is a Java-side substitute for nsIXULAppInfo, amongst
  * other things.
  *
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -1108,17 +1108,17 @@ abstract public class BrowserApp extends
     private void updateSideBarState() {
         if (mMainLayoutAnimator != null)
             mMainLayoutAnimator.stop();
 
         boolean isSideBar = (HardwareUtils.isTablet() && getOrientation() == Configuration.ORIENTATION_LANDSCAPE);
         final int sidebarWidth = getResources().getDimensionPixelSize(R.dimen.tabs_sidebar_width);
 
         ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mTabsPanel.getLayoutParams();
-        lp.width = (isSideBar ? sidebarWidth : ViewGroup.LayoutParams.FILL_PARENT);
+        lp.width = (isSideBar ? sidebarWidth : ViewGroup.LayoutParams.MATCH_PARENT);
         mTabsPanel.requestLayout();
 
         final boolean sidebarIsShown = (isSideBar && mTabsPanel.isShown());
         final int mainLayoutScrollX = (sidebarIsShown ? -sidebarWidth : 0);
         mMainLayout.scrollTo(mainLayoutScrollX, 0);
 
         mTabsPanel.setIsSideBar(isSideBar);
     }
--- a/mobile/android/base/DoorHangerPopup.java
+++ b/mobile/android/base/DoorHangerPopup.java
@@ -1,24 +1,26 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.util.GeckoEventListener;
+import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.widget.ArrowPopup;
 import org.mozilla.gecko.widget.DoorHanger;
 import org.mozilla.gecko.prompts.PromptInput;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import android.content.Context;
 import android.os.Build;
 import android.util.Log;
 import android.view.View;
 import android.widget.CheckBox;
 
 import java.util.HashSet;
 import java.util.List;
 
@@ -30,18 +32,18 @@ public class DoorHangerPopup extends Arr
 
     // Stores a set of all active DoorHanger notifications. A DoorHanger is
     // uniquely identified by its tabId and value.
     private HashSet<DoorHanger> mDoorHangers;
 
     // Whether or not the doorhanger popup is disabled.
     private boolean mDisabled;
 
-    DoorHangerPopup(GeckoApp activity) {
-        super(activity);
+    public DoorHangerPopup(Context context) {
+        super(context);
 
         mDoorHangers = new HashSet<DoorHanger>();
 
         EventDispatcher.getInstance().registerGeckoThreadListener(this,
             "Doorhanger:Add",
             "Doorhanger:Remove");
         Tabs.registerOnTabsChangedListener(this);
     }
@@ -76,27 +78,27 @@ public class DoorHangerPopup extends Arr
         try {
             if (event.equals("Doorhanger:Add")) {
                 final int tabId = geckoObject.getInt("tabID");
                 final String value = geckoObject.getString("value");
                 final String message = geckoObject.getString("message");
                 final JSONArray buttons = geckoObject.getJSONArray("buttons");
                 final JSONObject options = geckoObject.getJSONObject("options");
 
-                mActivity.runOnUiThread(new Runnable() {
+                ThreadUtils.postToUiThread(new Runnable() {
                     @Override
                     public void run() {
                         addDoorHanger(tabId, value, message, buttons, options);
                     }
                 });
             } else if (event.equals("Doorhanger:Remove")) {
                 final int tabId = geckoObject.getInt("tabID");
                 final String value = geckoObject.getString("value");
 
-                mActivity.runOnUiThread(new Runnable() {
+                ThreadUtils.postToUiThread(new Runnable() {
                     @Override
                     public void run() {
                         DoorHanger doorHanger = getDoorHanger(tabId, value);
                         if (doorHanger == null)
                             return;
 
                         removeDoorHanger(doorHanger);
                         updatePopup();
@@ -160,17 +162,17 @@ public class DoorHangerPopup extends Arr
         if (oldDoorHanger != null) {
             removeDoorHanger(oldDoorHanger);
         }
 
         if (!mInflated) {
             init();
         }
 
-        final DoorHanger newDoorHanger = new DoorHanger(mActivity, tabId, value);
+        final DoorHanger newDoorHanger = new DoorHanger(mContext, tabId, value);
         newDoorHanger.setMessage(message);
         newDoorHanger.setOptions(options);
 
         for (int i = 0; i < buttons.length(); i++) {
             try {
                 JSONObject buttonObject = buttons.getJSONObject(i);
                 String label = buttonObject.getString("label");
                 String tag = String.valueOf(buttonObject.getInt("callback"));
--- a/mobile/android/base/FormAssistPopup.java
+++ b/mobile/android/base/FormAssistPopup.java
@@ -251,23 +251,23 @@ public class FormAssistPopup extends Rel
 
         // These values correspond to the input box for which we want to
         // display the FormAssistPopup.
         int left = (int) (mX * zoom - aMetrics.viewportRectLeft + offset.x);
         int top = (int) (mY * zoom - aMetrics.viewportRectTop + offset.y);
         int width = (int) (mW * zoom);
         int height = (int) (mH * zoom);
 
-        int popupWidth = RelativeLayout.LayoutParams.FILL_PARENT;
+        int popupWidth = RelativeLayout.LayoutParams.MATCH_PARENT;
         int popupLeft = left < 0 ? 0 : left;
 
         FloatSize viewport = aMetrics.getSize();
 
         // For autocomplete suggestions, if the input is smaller than the screen-width,
-        // shrink the popup's width. Otherwise, keep it as FILL_PARENT.
+        // shrink the popup's width. Otherwise, keep it as MATCH_PARENT.
         if ((mPopupType == PopupType.AUTOCOMPLETE) && (left + width) < viewport.width) {
             popupWidth = left < 0 ? left + width : width;
 
             // Ensure the popup has a minimum width.
             if (popupWidth < sAutoCompleteMinWidth) {
                 popupWidth = sAutoCompleteMinWidth;
 
                 // Move the popup to the left if there isn't enough room for it.
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -53,17 +53,16 @@ import org.mozilla.gecko.updater.UpdateS
 import org.mozilla.gecko.util.ActivityResultHandler;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.FileUtils;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.util.UiAsyncTask;
 import org.mozilla.gecko.webapp.EventListener;
 import org.mozilla.gecko.webapp.UninstallListener;
 import org.mozilla.gecko.widget.ButtonToast;
 
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.Context;
@@ -106,17 +105,16 @@ import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.OrientationEventListener;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
-import android.view.TextureView;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.AbsoluteLayout;
 import android.widget.FrameLayout;
 import android.widget.ListView;
@@ -170,17 +168,16 @@ public abstract class GeckoApp
     static private final String LOCATION_URL = "https://location.services.mozilla.com/v1/submit";
 
     // Delay before running one-time "cleanup" tasks that may be needed
     // after a version upgrade.
     private static final int CLEANUP_DEFERRAL_SECONDS = 15;
 
     protected RelativeLayout mMainLayout;
     protected RelativeLayout mGeckoLayout;
-    public View getView() { return mGeckoLayout; }
     private View mCameraView;
     private OrientationEventListener mCameraOrientationEventListener;
     public List<GeckoAppShell.AppStateListener> mAppStateListeners;
     protected MenuPanel mMenuPanel;
     protected Menu mMenu;
     protected GeckoProfile mProfile;
     protected boolean mIsRestoringActivity;
 
@@ -838,18 +835,18 @@ public abstract class GeckoApp
         view.setWillNotDraw(false);
         if (view instanceof SurfaceView) {
             ((SurfaceView) view).setZOrderOnTop(true);
         }
 
         mFullScreenPluginContainer = new FullScreenHolder(this);
 
         FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
-                            ViewGroup.LayoutParams.FILL_PARENT,
-                            ViewGroup.LayoutParams.FILL_PARENT,
+                            ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.MATCH_PARENT,
                             Gravity.CENTER);
         mFullScreenPluginContainer.addView(view, layoutParams);
 
 
         FrameLayout decor = (FrameLayout)getWindow().getDecorView();
         decor.addView(mFullScreenPluginContainer, layoutParams);
 
         mFullScreenPluginView = view;
--- a/mobile/android/base/GeckoProfile.java
+++ b/mobile/android/base/GeckoProfile.java
@@ -1,70 +1,83 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko;
 
-import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
-import org.mozilla.gecko.GeckoProfileDirectories.NoSuchProfileException;
-import org.mozilla.gecko.Telemetry;
-import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.util.INIParser;
-import org.mozilla.gecko.util.INISection;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Log;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.nio.charset.Charset;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
 
+import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
+import org.mozilla.gecko.GeckoProfileDirectories.NoSuchProfileException;
+import org.mozilla.gecko.db.BrowserDB;
+import org.mozilla.gecko.distribution.Distribution;
+import org.mozilla.gecko.mozglue.RobocopTarget;
+import org.mozilla.gecko.util.INIParser;
+import org.mozilla.gecko.util.INISection;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+
 public final class GeckoProfile {
     private static final String LOGTAG = "GeckoProfile";
 
     // Used to "lock" the guest profile, so that we'll always restart in it
     private static final String LOCK_FILE_NAME = ".active_lock";
     public static final String DEFAULT_PROFILE = "default";
     private static final String GUEST_PROFILE = "guest";
 
     private static HashMap<String, GeckoProfile> sProfileCache = new HashMap<String, GeckoProfile>();
     private static String sDefaultProfileName = null;
 
+    // Caches the guest profile dir.
+    private static File sGuestDir = null;
+    private static GeckoProfile sGuestProfile = null;
+
     public static boolean sIsUsingCustomProfile = false;
+
     private final String mName;
     private final File mMozillaDir;
-    private File mProfileDir;             // Not final because this is lazily computed.
+    private final boolean mIsWebAppProfile;
+    private final Context mApplicationContext;
+
+    /**
+     * Access to this member should be synchronized to avoid
+     * races during creation -- particularly between getDir and GeckoView#init.
+     *
+     * Not final because this is lazily computed. 
+     */
+    private File mProfileDir;
+
+    // Caches whether or not a profile is "locked".
+    // Only used by the guest profile to determine if it should be reused or
+    // deleted on startup.
+    // These are volatile for an incremental improvement in thread safety,
+    // but this is not a complete solution for concurrency.
+    private volatile LockState mLocked = LockState.UNDEFINED;
+    private volatile boolean mInGuestMode = false;
 
     // Constants to cache whether or not a profile is "locked".
     private enum LockState {
         LOCKED,
         UNLOCKED,
         UNDEFINED
     };
 
-    // Caches whether or not a profile is "locked". Only used by the guest profile to determine if it should
-    // be reused or deleted on startup
-    private LockState mLocked = LockState.UNDEFINED;
-
-    // Caches the guest profile dir.
-    private static File sGuestDir = null;
-    private static GeckoProfile sGuestProfile = null;
-
-    private boolean mInGuestMode = false;
-
-
     public static GeckoProfile get(Context context) {
         boolean isGeckoApp = false;
         try {
             isGeckoApp = context instanceof GeckoApp;
         } catch (NoClassDefFoundError ex) {}
 
         if (isGeckoApp) {
             // Check for a cached profile on this context already
@@ -103,27 +116,29 @@ public final class GeckoProfile {
         synchronized (sProfileCache) {
             GeckoProfile profile = sProfileCache.get(profileName);
             if (profile != null)
                 return profile;
         }
         return get(context, profileName, (File)null);
     }
 
+    @RobocopTarget
     public static GeckoProfile get(Context context, String profileName, String profilePath) {
         File dir = null;
         if (!TextUtils.isEmpty(profilePath)) {
             dir = new File(profilePath);
             if (!dir.exists() || !dir.isDirectory()) {
                 Log.w(LOGTAG, "requested profile directory missing: " + profilePath);
             }
         }
         return get(context, profileName, dir);
     }
 
+    @RobocopTarget
     public static GeckoProfile get(Context context, String profileName, File profileDir) {
         if (context == null) {
             throw new IllegalArgumentException("context must be non-null");
         }
 
         // if no profile was passed in, look for the default profile listed in profiles.ini
         // if that doesn't exist, look for a profile called 'default'
         if (TextUtils.isEmpty(profileName) && profileDir == null) {
@@ -150,16 +165,21 @@ public final class GeckoProfile {
             } else {
                 profile.setDir(profileDir);
             }
             return profile;
         }
     }
 
     public static boolean removeProfile(Context context, String profileName) {
+        if (profileName == null) {
+            Log.w(LOGTAG, "Unable to remove profile: null profile name.");
+            return false;
+        }
+
         final boolean success;
         try {
             success = new GeckoProfile(context, profileName).remove();
         } catch (NoMozillaDirectoryException e) {
             Log.w(LOGTAG, "Unable to remove profile: no Mozilla directory.", e);
             return true;
         }
 
@@ -261,65 +281,81 @@ public final class GeckoProfile {
             }
         }
 
         // Even if this is a dir, it should now be empty and delete should work
         return file.delete();
     }
 
     private GeckoProfile(Context context, String profileName) throws NoMozillaDirectoryException {
+        if (TextUtils.isEmpty(profileName)) {
+            throw new IllegalArgumentException("Unable to create GeckoProfile for empty profile name.");
+        }
+
+        mApplicationContext = context.getApplicationContext();
         mName = profileName;
+        mIsWebAppProfile = profileName.startsWith("webapp");
         mMozillaDir = GeckoProfileDirectories.getMozillaDirectory(context);
     }
 
     // Warning, Changing the lock file state from outside apis will cause this to become out of sync
     public boolean locked() {
         if (mLocked != LockState.UNDEFINED) {
             return mLocked == LockState.LOCKED;
         }
 
-        // Don't use getDir() as it will create a dir if none exists
-        if (mProfileDir != null && mProfileDir.exists()) {
+        boolean profileExists;
+        synchronized (this) {
+            profileExists = mProfileDir != null && mProfileDir.exists();
+        }
+
+        // Don't use getDir() as it will create a dir if none exists.
+        if (profileExists) {
             File lockFile = new File(mProfileDir, LOCK_FILE_NAME);
             boolean res = lockFile.exists();
             mLocked = res ? LockState.LOCKED : LockState.UNLOCKED;
         } else {
             mLocked = LockState.UNLOCKED;
         }
 
         return mLocked == LockState.LOCKED;
     }
 
     public boolean lock() {
         try {
             // If this dir doesn't exist getDir will create it for us
-            File lockFile = new File(getDir(), LOCK_FILE_NAME);
-            boolean result = lockFile.createNewFile();
+            final File lockFile = new File(getDir(), LOCK_FILE_NAME);
+            final boolean result = lockFile.createNewFile();
             if (result) {
                 mLocked = LockState.LOCKED;
             } else {
                 mLocked = LockState.UNLOCKED;
             }
             return result;
         } catch(IOException ex) {
             Log.e(LOGTAG, "Error locking profile", ex);
         }
         mLocked = LockState.UNLOCKED;
         return false;
     }
 
     public boolean unlock() {
-        // Don't use getDir() as it will create a dir
-        if (mProfileDir == null || !mProfileDir.exists()) {
+        final File profileDir;
+        synchronized (this) {
+            // Don't use getDir() as it will create a dir.
+            profileDir = mProfileDir;
+        }
+
+        if (profileDir == null || !profileDir.exists()) {
             return true;
         }
 
         try {
-            File lockFile = new File(mProfileDir, LOCK_FILE_NAME);
-            boolean result = delete(lockFile);
+            final File lockFile = new File(profileDir, LOCK_FILE_NAME);
+            final boolean result = delete(lockFile);
             if (result) {
                 mLocked = LockState.UNLOCKED;
             } else {
                 mLocked = LockState.LOCKED;
             }
             return result;
         } catch(IOException ex) {
             Log.e(LOGTAG, "Error unlocking profile", ex);
@@ -329,17 +365,19 @@ public final class GeckoProfile {
     }
 
     public boolean inGuestMode() {
         return mInGuestMode;
     }
 
     private void setDir(File dir) {
         if (dir != null && dir.exists() && dir.isDirectory()) {
-            mProfileDir = dir;
+            synchronized (this) {
+                mProfileDir = dir;
+            }
         }
     }
 
     public String getName() {
         return mName;
     }
 
     public synchronized File getDir() {
@@ -440,26 +478,28 @@ public final class GeckoProfile {
             return sb.toString();
         } finally {
             fr.close();
         }
     }
 
     private boolean remove() {
         try {
-            final File dir = getDir();
-            if (dir.exists()) {
-                delete(dir);
-            }
+            synchronized (this) {
+                final File dir = getDir();
+                if (dir.exists()) {
+                    delete(dir);
+                }
 
-            try {
-                mProfileDir = findProfileDir();
-            } catch (NoSuchProfileException noSuchProfile) {
-                // If the profile doesn't exist, there's nothing left for us to do.
-                return false;
+                try {
+                    mProfileDir = findProfileDir();
+                } catch (NoSuchProfileException noSuchProfile) {
+                    // If the profile doesn't exist, there's nothing left for us to do.
+                    return false;
+                }
             }
 
             final INIParser parser = GeckoProfileDirectories.getProfilesINI(mMozillaDir);
             final Hashtable<String, INISection> sections = parser.getSections();
             for (Enumeration<INISection> e = sections.elements(); e.hasMoreElements();) {
                 final INISection section = e.nextElement();
                 String name = section.getStringProperty("Name");
 
@@ -571,39 +611,73 @@ public final class GeckoProfile {
         profileSection.setProperty("Path", saltedName);
 
         if (parser.getSection("General") == null) {
             INISection generalSection = new INISection("General");
             generalSection.setProperty("StartWithLastProfile", 1);
             parser.addSection(generalSection);
         }
 
-        if (!isDefaultSet && !mName.startsWith("webapp")) {
+        if (!isDefaultSet && !mIsWebAppProfile) {
             // only set as default if this is the first non-webapp
             // profile we're creating
             profileSection.setProperty("Default", 1);
 
             // We have no intention of stopping this session. The FIRSTRUN session
             // ends when the browsing session/activity has ended. All events
             // during firstrun will be tagged as FIRSTRUN.
             Telemetry.startUISession(TelemetryContract.Session.FIRSTRUN);
         }
 
         parser.addSection(profileSection);
         parser.write();
 
+        // Trigger init for non-webapp profiles.
+        if (!mIsWebAppProfile) {
+            enqueueInitialization();
+        }
+
         // Write out profile creation time, mirroring the logic in nsToolkitProfileService.
         try {
             FileOutputStream stream = new FileOutputStream(profileDir.getAbsolutePath() + File.separator + "times.json");
             OutputStreamWriter writer = new OutputStreamWriter(stream, Charset.forName("UTF-8"));
             try {
                 writer.append("{\"created\": " + System.currentTimeMillis() + "}\n");
             } finally {
                 writer.close();
             }
         } catch (Exception e) {
             // Best-effort.
             Log.w(LOGTAG, "Couldn't write times.json.", e);
         }
 
         return profileDir;
     }
+
+    /**
+     * This method is called once, immediately before creation of the profile
+     * directory completes.
+     *
+     * It queues up work to be done in the background to prepare the profile,
+     * such as adding default bookmarks.
+     *
+     * This is public for use *from tests only*!
+     */
+    @RobocopTarget
+    public void enqueueInitialization() {
+        Log.i(LOGTAG, "Enqueuing profile init.");
+        final Context context = mApplicationContext;
+
+        // Add everything when we're done loading the distribution.
+        final Distribution distribution = Distribution.getInstance(context);
+        distribution.addOnDistributionReadyCallback(new Runnable() {
+            @Override
+            public void run() {
+                Log.d(LOGTAG, "Running post-distribution task: bookmarks.");
+
+                final ContentResolver cr = context.getContentResolver();
+
+                final int offset = BrowserDB.addDistributionBookmarks(cr, distribution, 0);
+                BrowserDB.addDefaultBookmarks(context, cr, offset);
+            }
+        });
+    }
 }
--- a/mobile/android/base/crashreporter/res/layout/crash_reporter.xml
+++ b/mobile/android/base/crashreporter/res/layout/crash_reporter.xml
@@ -1,24 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
             android:fillViewport="true">
 
-    <LinearLayout android:layout_width="fill_parent"
+    <LinearLayout android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:orientation="vertical"
                   android:background="@color/background_normal">
         
-        <LinearLayout android:layout_width="fill_parent"
+        <LinearLayout android:layout_width="match_parent"
                       android:layout_height="0dp"
                       android:orientation="vertical"
                       android:padding="10dp"
                       android:layout_weight="1">
 
             <TextView android:layout_width="wrap_content"
                       android:layout_height="wrap_content"
                       android:padding="10dip"
@@ -39,17 +39,17 @@
                       android:layout_height="wrap_content"
                       android:checked="true"
                       android:textColor="@color/primary_text"
                       android:layout_marginBottom="10dp"
                       android:text="@string/crash_send_report_message3"/>
 
             <EditText android:id="@+id/comment"
                       style="@style/CrashReporter.EditText"
-                      android:layout_width="fill_parent"
+                      android:layout_width="match_parent"
                       android:layout_height="wrap_content"
                       android:ems="10"
                       android:inputType="textMultiLine"
                       android:lines="5"
                       android:gravity="top"
                       android:layout_marginLeft="8dp"
                       android:layout_marginRight="8dp"
                       android:layout_marginBottom="10dp"
@@ -69,49 +69,49 @@
                       android:textColor="@color/primary_text"
                       android:textAppearance="@style/TextAppearance"
                       android:layout_marginBottom="10dp"
                       android:text="@string/crash_allow_contact2"/>
 
             <org.mozilla.gecko.widget.ClickableWhenDisabledEditText
                     android:id="@+id/email"
                     style="@style/CrashReporter.EditText"
-                    android:layout_width="fill_parent"
+                    android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:ems="10"
                     android:inputType="textEmailAddress"
                     android:layout_marginLeft="8dp"
                     android:layout_marginRight="8dp"
                     android:enabled="false"
                     android:clickable="true"
                     android:hint="@string/crash_email" />
 
         </LinearLayout>
         
-        <View android:layout_width="fill_parent"
+        <View android:layout_width="match_parent"
               android:layout_height="1dp"
               android:background="#999" />
 
-        <LinearLayout android:layout_width="fill_parent"
+        <LinearLayout android:layout_width="match_parent"
                       android:layout_height="wrap_content"
                       android:orientation="horizontal"
                       android:layout_gravity="bottom">
 
             <Button android:id="@+id/close"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
                     android:layout_weight="1.0"
                     android:padding="15dp"
                     android:onClick="onCloseClick"
                     android:text="@string/crash_close_label"
                     android:textAppearance="?android:attr/textAppearance"
                     android:background="@drawable/action_bar_button"/>
 
             <View android:layout_width="1dp"
-                  android:layout_height="fill_parent"
+                  android:layout_height="match_parent"
                   android:background="#999" />
         
             <Button android:id="@+id/restart"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
                     android:layout_weight="1.0"
                     android:padding="15dp"
                     android:onClick="onRestartClick"
--- a/mobile/android/base/db/BrowserDB.java
+++ b/mobile/android/base/db/BrowserDB.java
@@ -5,21 +5,23 @@
 
 package org.mozilla.gecko.db;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import org.mozilla.gecko.db.BrowserContract.ExpirePriority;
 import org.mozilla.gecko.db.SuggestedSites;
+import org.mozilla.gecko.distribution.Distribution;
 import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
 import org.mozilla.gecko.mozglue.RobocopTarget;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.Color;
 
 public class BrowserDB {
     private static boolean sAreContentProvidersEnabled = true;
 
@@ -133,27 +135,38 @@ public class BrowserDB {
         public void unpinSite(ContentResolver cr, int position);
 
         public void unpinAllSites(ContentResolver cr);
 
         public Cursor getPinnedSites(ContentResolver cr, int limit);
 
         @RobocopTarget
         public Cursor getBookmarkForUrl(ContentResolver cr, String url);
+
+        public int addDefaultBookmarks(Context context, ContentResolver cr, int offset);
+        public int addDistributionBookmarks(ContentResolver cr, Distribution distribution, int offset);
     }
 
     static {
         // Forcing local DB no option to switch to Android DB for now
         sDb = null;
     }
 
     public static void initialize(String profile) {
         sDb = new LocalBrowserDB(profile);
     }
 
+    public static int addDefaultBookmarks(Context context, ContentResolver cr, final int offset) {
+        return sDb.addDefaultBookmarks(context, cr, offset);
+    }
+
+    public static int addDistributionBookmarks(ContentResolver cr, Distribution distribution, int offset) {
+        return sDb.addDistributionBookmarks(cr, distribution, offset);
+    }
+
     public static void setSuggestedSites(SuggestedSites suggestedSites) {
         sSuggestedSites = suggestedSites;
     }
 
     public static boolean hideSuggestedSite(String url) {
         return sSuggestedSites.hideSite(url);
     }
 
--- a/mobile/android/base/db/BrowserDatabaseHelper.java
+++ b/mobile/android/base/db/BrowserDatabaseHelper.java
@@ -1,54 +1,38 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */
 /* 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/. */
 
 package org.mozilla.gecko.db;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.db.BrowserContract.Combined;
 import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
 import org.mozilla.gecko.db.BrowserContract.Favicons;
 import org.mozilla.gecko.db.BrowserContract.History;
 import org.mozilla.gecko.db.BrowserContract.Obsolete;
 import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
 import org.mozilla.gecko.db.BrowserContract.Thumbnails;
-import org.mozilla.gecko.distribution.Distribution;
-import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.util.GeckoJarReader;
-import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
-import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Build;
-import android.text.TextUtils;
 import android.util.Log;
 
 
 final class BrowserDatabaseHelper extends SQLiteOpenHelper {
 
     private static final String LOGTAG = "GeckoBrowserDBHelper";
     public static final int DATABASE_VERSION = 18;
     public static final String DATABASE_NAME = "browser.db";
@@ -759,135 +743,19 @@ final class BrowserDatabaseHelper extend
         createBookmarksWithFaviconsView(db);
         createHistoryWithFaviconsView(db);
         createCombinedViewOn16(db);
 
         createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID,
             R.string.bookmarks_folder_places, 0);
 
         createOrUpdateAllSpecialFolders(db);
-
-        int offset = createDefaultBookmarks(db, 0);
-
-        // We'd like to create distribution bookmarks before our own default bookmarks,
-        // but we won't necessarily have loaded the distribution yet. Oh well.
-        enqueueDistributionBookmarkLoad(db, offset);
-
         createReadingListTable(db);
     }
 
-    private String getLocalizedProperty(JSONObject bookmark, String property, Locale locale) throws JSONException {
-        // Try the full locale
-        String fullLocale = property + "." + locale.toString();
-        if (bookmark.has(fullLocale)) {
-            return bookmark.getString(fullLocale);
-        }
-        // Try without a variant
-        if (!TextUtils.isEmpty(locale.getVariant())) {
-            String noVariant = fullLocale.substring(0, fullLocale.lastIndexOf("_"));
-            if (bookmark.has(noVariant)) {
-                return bookmark.getString(noVariant);
-            }
-        }
-        // Try just the language
-        String lang = property + "." + locale.getLanguage();
-        if (bookmark.has(lang)) {
-            return bookmark.getString(lang);
-        }
-        // Default to the non-localized property name
-        return bookmark.getString(property);
-    }
-
-    // We can't rely on the distribution file having been loaded,
-    // so we delegate that work to the distribution handler.
-    private void enqueueDistributionBookmarkLoad(final SQLiteDatabase db, final int start) {
-        final Distribution distribution = Distribution.getInstance(mContext);
-        distribution.addOnDistributionReadyCallback(new Runnable() {
-            @Override
-            public void run() {
-                Log.d(LOGTAG, "Running post-distribution task: bookmarks.");
-                if (!distribution.exists()) {
-                    return;
-                }
-
-                // This runnable is always executed on the background thread,
-                // thanks to Distribution's guarantees.
-                // Yes, the user might have added a bookmark in the interim,
-                // in which case `start` will be wrong. Sync will need to fix
-                // up the indices.
-                createDistributionBookmarks(distribution, db, start);
-            }
-        });
-    }
-
-    /**
-     * Fetch distribution bookmarks and insert them into the database.
-     *
-     * @param db the destination database.
-     * @param start the initial index at which to insert.
-     * @return the number of inserted bookmarks.
-     */
-    private int createDistributionBookmarks(Distribution distribution, SQLiteDatabase db, int start) {
-        JSONArray bookmarks = distribution.getBookmarks();
-        if (bookmarks == null) {
-            return 0;
-        }
-
-        Locale locale = Locale.getDefault();
-        int pos = start;
-        Integer mobileFolderId = getMobileFolderId(db);
-        if (mobileFolderId == null) {
-            Log.e(LOGTAG, "Error creating distribution bookmarks: mobileFolderId is null.");
-            return 0;
-        }
-
-        for (int i = 0; i < bookmarks.length(); i++) {
-            try {
-                final JSONObject bookmark = bookmarks.getJSONObject(i);
-
-                String title = getLocalizedProperty(bookmark, "title", locale);
-                final String url = getLocalizedProperty(bookmark, "url", locale);
-                createBookmark(db, title, url, pos, mobileFolderId);
-
-                if (bookmark.has("pinned")) {
-                    try {
-                        // Create a fake bookmark in the hidden pinned folder to pin bookmark
-                        // to about:home top sites. Pass pos as the pinned position to pin
-                        // sites in the order that bookmarks are specified in bookmarks.json.
-                        if (bookmark.getBoolean("pinned")) {
-                            createBookmark(db, title, url, pos, Bookmarks.FIXED_PINNED_LIST_ID);
-                        }
-                    } catch (JSONException e) {
-                        Log.e(LOGTAG, "Error pinning bookmark to top sites.", e);
-                    }
-                }
-
-                pos++;
-
-                // Return early if there is no icon for this bookmark.
-                if (!bookmark.has("icon")) {
-                    continue;
-                }
-
-                try {
-                    final String iconData = bookmark.getString("icon");
-                    final Bitmap icon = BitmapUtils.getBitmapFromDataURI(iconData);
-                    if (icon != null) {
-                        createFavicon(db, url, icon);
-                    }
-                } catch (JSONException e) {
-                    Log.e(LOGTAG, "Error creating distribution bookmark icon.", e);
-                }
-            } catch (JSONException e) {
-                Log.e(LOGTAG, "Error creating distribution bookmark.", e);
-            }
-        }
-        return pos - start;
-    }
-
     private void createReadingListTable(SQLiteDatabase db) {
         debug("Creating " + TABLE_READING_LIST + " table");
 
         db.execSQL("CREATE TABLE " + TABLE_READING_LIST + "(" +
                     ReadingListItems._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                     ReadingListItems.URL + " TEXT NOT NULL, " +
                     ReadingListItems.TITLE + " TEXT, " +
                     ReadingListItems.EXCERPT + " TEXT, " +
@@ -899,149 +767,16 @@ final class BrowserDatabaseHelper extend
                     ReadingListItems.LENGTH + " INTEGER DEFAULT 0 ); ");
 
         db.execSQL("CREATE INDEX reading_list_url ON " + TABLE_READING_LIST + "("
                 + ReadingListItems.URL + ")");
         db.execSQL("CREATE UNIQUE INDEX reading_list_guid ON " + TABLE_READING_LIST + "("
                 + ReadingListItems.GUID + ")");
     }
 
-    /**
-     * Insert default bookmarks into the database.
-     *
-     * @param db the destination database.
-     * @param start the initial index at which to insert.
-     * @return the number of inserted bookmarks.
-     */
-    private int createDefaultBookmarks(SQLiteDatabase db, int start) {
-        Class<?> stringsClass = R.string.class;
-        Field[] fields = stringsClass.getFields();
-        Pattern p = Pattern.compile("^bookmarkdefaults_title_");
-
-        Integer mobileFolderId = getMobileFolderId(db);
-        if (mobileFolderId == null) {
-            Log.e(LOGTAG, "Error creating default bookmarks: mobileFolderId is null");
-            return 0;
-        }
-
-        int pos = start;
-
-        for (int i = 0; i < fields.length; i++) {
-            final String name = fields[i].getName();
-            Matcher m = p.matcher(name);
-            if (!m.find()) {
-                continue;
-            }
-            try {
-                int titleid = fields[i].getInt(null);
-                String title = mContext.getString(titleid);
-
-                Field urlField = stringsClass.getField(name.replace("_title_", "_url_"));
-                int urlId = urlField.getInt(null);
-                final String url = mContext.getString(urlId);
-                createBookmark(db, title, url, pos, mobileFolderId);
-
-                // Create icons in a separate thread to avoid blocking about:home on startup.
-                ThreadUtils.postToBackgroundThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        SQLiteDatabase db = getWritableDatabase();
-                        Bitmap icon = getDefaultFaviconFromPath(name);
-                        if (icon == null) {
-                            icon = getDefaultFaviconFromDrawable(name);
-                        }
-                        if (icon != null) {
-                            createFavicon(db, url, icon);
-                        }
-                    }
-                });
-                pos++;
-            } catch (java.lang.IllegalAccessException ex) {
-                Log.e(LOGTAG, "Can't create bookmark " + name, ex);
-            } catch (java.lang.NoSuchFieldException ex) {
-                Log.e(LOGTAG, "Can't create bookmark " + name, ex);
-            }
-        }
-
-        return pos - start;
-    }
-
-    private void createBookmark(SQLiteDatabase db, String title, String url, int pos, int parent) {
-        ContentValues bookmarkValues = new ContentValues();
-        bookmarkValues.put(Bookmarks.PARENT, parent);
-
-        long now = System.currentTimeMillis();
-        bookmarkValues.put(Bookmarks.DATE_CREATED, now);
-        bookmarkValues.put(Bookmarks.DATE_MODIFIED, now);
-
-        bookmarkValues.put(Bookmarks.TITLE, title);
-        bookmarkValues.put(Bookmarks.URL, url);
-        bookmarkValues.put(Bookmarks.GUID, Utils.generateGuid());
-        bookmarkValues.put(Bookmarks.POSITION, pos);
-        db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.TITLE, bookmarkValues);
-    }
-
-    private void createFavicon(SQLiteDatabase db, String url, Bitmap icon) {
-        ByteArrayOutputStream stream = new ByteArrayOutputStream();
-
-        ContentValues iconValues = new ContentValues();
-        iconValues.put(Favicons.PAGE_URL, url);
-
-        byte[] data = null;
-        if (icon.compress(Bitmap.CompressFormat.PNG, 100, stream)) {
-            data = stream.toByteArray();
-        } else {
-            Log.w(LOGTAG, "Favicon compression failed.");
-        }
-        iconValues.put(Favicons.DATA, data);
-
-        insertFavicon(db, iconValues);
-    }
-
-    private Bitmap getDefaultFaviconFromPath(String name) {
-        Class<?> stringClass = R.string.class;
-        try {
-            // Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_*
-            Field faviconField = stringClass.getField(name.replace("_title_", "_favicon_"));
-            if (faviconField == null) {
-                return null;
-            }
-            int faviconId = faviconField.getInt(null);
-            String path = mContext.getString(faviconId);
-
-            String apkPath = mContext.getPackageResourcePath();
-            File apkFile = new File(apkPath);
-            String bitmapPath = "jar:jar:" + apkFile.toURI() + "!/" + AppConstants.OMNIJAR_NAME + "!/" + path;
-            return GeckoJarReader.getBitmap(mContext.getResources(), bitmapPath);
-        } catch (java.lang.IllegalAccessException ex) {
-            Log.e(LOGTAG, "[Path] Can't create favicon " + name, ex);
-        } catch (java.lang.NoSuchFieldException ex) {
-            // If the field does not exist, that means we intend to load via a drawable
-        }
-        return null;
-    }
-
-    private Bitmap getDefaultFaviconFromDrawable(String name) {
-        Class<?> drawablesClass = R.drawable.class;
-        try {
-            // Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_*
-            Field faviconField = drawablesClass.getField(name.replace("_title_", "_favicon_"));
-            if (faviconField == null) {
-                return null;
-            }
-            int faviconId = faviconField.getInt(null);
-            return BitmapUtils.decodeResource(mContext, faviconId);
-        } catch (java.lang.IllegalAccessException ex) {
-            Log.e(LOGTAG, "[Drawable] Can't create favicon " + name, ex);
-        } catch (java.lang.NoSuchFieldException ex) {
-            // If the field does not exist, that means we intend to load via a file path
-        }
-        return null;
-    }
-
     private void createOrUpdateAllSpecialFolders(SQLiteDatabase db) {
         createOrUpdateSpecialFolder(db, Bookmarks.MOBILE_FOLDER_GUID,
             R.string.bookmarks_folder_mobile, 0);
         createOrUpdateSpecialFolder(db, Bookmarks.TOOLBAR_FOLDER_GUID,
             R.string.bookmarks_folder_toolbar, 1);
         createOrUpdateSpecialFolder(db, Bookmarks.MENU_FOLDER_GUID,
             R.string.bookmarks_folder_menu, 2);
         createOrUpdateSpecialFolder(db, Bookmarks.TAGS_FOLDER_GUID,
@@ -1769,17 +1504,17 @@ final class BrowserDatabaseHelper extend
                 cursor = db.rawQuery("PRAGMA journal_mode=PERSIST", null);
             } finally {
                 if (cursor != null)
                     cursor.close();
             }
         }
     }
 
-    static final String qualifyColumn(String table, String column) {
+    private static final String qualifyColumn(String table, String column) {
         return DBUtils.qualifyColumn(table, column);
     }
 
     // Calculate these once, at initialization. isLoggable is too expensive to
     // have in-line in each log call.
     private static boolean logDebug   = Log.isLoggable(LOGTAG, Log.DEBUG);
     private static boolean logVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE);
     protected static void trace(String message) {
@@ -1809,59 +1544,16 @@ final class BrowserDatabaseHelper extend
 
             return c.getInt(c.getColumnIndex(Bookmarks._ID));
         } finally {
             if (c != null)
                 c.close();
         }
     }
 
-    private long insertFavicon(SQLiteDatabase db, ContentValues values) {
-        // This method is a dupicate of BrowserProvider.insertFavicon.
-        // If changes are needed, please update both
-        String faviconUrl = values.getAsString(Favicons.URL);
-        String pageUrl = null;
-        long faviconId;
-
-        trace("Inserting favicon for URL: " + faviconUrl);
-
-        DBUtils.stripEmptyByteArray(values, Favicons.DATA);
-
-        // Extract the page URL from the ContentValues
-        if (values.containsKey(Favicons.PAGE_URL)) {
-            pageUrl = values.getAsString(Favicons.PAGE_URL);
-            values.remove(Favicons.PAGE_URL);
-        }
-
-        // If no URL is provided, insert using the default one.
-        if (TextUtils.isEmpty(faviconUrl) && !TextUtils.isEmpty(pageUrl)) {
-            values.put(Favicons.URL, org.mozilla.gecko.favicons.Favicons.guessDefaultFaviconURL(pageUrl));
-        }
-
-        long now = System.currentTimeMillis();
-        values.put(Favicons.DATE_CREATED, now);
-        values.put(Favicons.DATE_MODIFIED, now);
-        faviconId = db.insertOrThrow(TABLE_FAVICONS, null, values);
-
-        if (pageUrl != null) {
-            ContentValues updateValues = new ContentValues(1);
-            updateValues.put(FaviconColumns.FAVICON_ID, faviconId);
-            db.update(TABLE_HISTORY,
-                      updateValues,
-                      History.URL + " = ?",
-                      new String[] { pageUrl });
-            db.update(TABLE_BOOKMARKS,
-                      updateValues,
-                      Bookmarks.URL + " = ?",
-                      new String[] { pageUrl });
-        }
-
-        return faviconId;
-    }
-
     private interface BookmarkMigrator {
         public void updateForNewTable(ContentValues bookmark);
     }
 
     private class BookmarkMigrator3to4 implements BookmarkMigrator {
         @Override
         public void updateForNewTable(ContentValues bookmark) {
             Integer isFolder = bookmark.getAsInteger("folder");
--- a/mobile/android/base/db/BrowserProvider.java
+++ b/mobile/android/base/db/BrowserProvider.java
@@ -7,22 +7,20 @@ package org.mozilla.gecko.db;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserContract.CommonColumns;
 import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
 import org.mozilla.gecko.db.BrowserContract.Favicons;
 import org.mozilla.gecko.db.BrowserContract.History;
 import org.mozilla.gecko.db.BrowserContract.Schema;
-import org.mozilla.gecko.db.BrowserContract.SyncColumns;
 import org.mozilla.gecko.db.BrowserContract.Thumbnails;
 import org.mozilla.gecko.sync.Utils;
 
 import android.app.SearchManager;
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderResult;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -228,20 +226,16 @@ public class BrowserProvider extends Sha
                 Combined.TITLE + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_1);
         map.put(SearchManager.SUGGEST_COLUMN_TEXT_2_URL,
                 Combined.URL + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
         map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA,
                 Combined.URL + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA);
         SEARCH_SUGGEST_PROJECTION_MAP = Collections.unmodifiableMap(map);
     }
 
-    static final String qualifyColumn(String table, String column) {
-        return table + "." + column;
-    }
-
     private static boolean hasFaviconsInProjection(String[] projection) {
         if (projection == null) return true;
         for (int i = 0; i < projection.length; ++i) {
             if (projection[i].equals(FaviconColumns.FAVICON) ||
                 projection[i].equals(FaviconColumns.FAVICON_URL))
                 return true;
         }
 
@@ -815,17 +809,17 @@ public class BrowserProvider extends Sha
 
     /**
      * Update the positions of bookmarks in batches.
      *
      * Begins and ends its own transactions.
      *
      * @see #updateBookmarkPositionsInTransaction(SQLiteDatabase, String[], int, int)
      */
-    int updateBookmarkPositions(Uri uri, String[] guids) {
+    private int updateBookmarkPositions(Uri uri, String[] guids) {
         if (guids == null) {
             return 0;
         }
 
         int guidsCount = guids.length;
         if (guidsCount == 0) {
             return 0;
         }
@@ -914,17 +908,17 @@ public class BrowserProvider extends Sha
         trace("Updating bookmark parents of " + selection + " (" + selectionArgs[0] + ")");
         String where = Bookmarks._ID + " IN (" +
                        " SELECT DISTINCT " + Bookmarks.PARENT +
                        " FROM " + TABLE_BOOKMARKS +
                        " WHERE " + selection + " )";
         return db.update(TABLE_BOOKMARKS, values, where, selectionArgs);
     }
 
-    long insertBookmark(Uri uri, ContentValues values) {
+    private long insertBookmark(Uri uri, ContentValues values) {
         // Generate values if not specified. Don't overwrite
         // if specified by caller.
         long now = System.currentTimeMillis();
         if (!values.containsKey(Bookmarks.DATE_CREATED)) {
             values.put(Bookmarks.DATE_CREATED, now);
         }
 
         if (!values.containsKey(Bookmarks.DATE_MODIFIED)) {
@@ -945,34 +939,34 @@ public class BrowserProvider extends Sha
 
         debug("Inserting bookmark in database with URL: " + url);
         final SQLiteDatabase db = getWritableDatabase(uri);
         beginWrite(db);
         return db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.TITLE, values);
     }
 
 
-    int updateOrInsertBookmark(Uri uri, ContentValues values, String selection,
+    private int updateOrInsertBookmark(Uri uri, ContentValues values, String selection,
             String[] selectionArgs) {
         int updated = updateBookmarks(uri, values, selection, selectionArgs);
         if (updated > 0) {
             return updated;
         }
 
         // Transaction already begun by updateBookmarks.
         if (0 <= insertBookmark(uri, values)) {
             // We 'updated' one row.
             return 1;
         }
 
         // If something went wrong, then we updated zero rows.
         return 0;
     }
 
-    int updateBookmarks(Uri uri, ContentValues values, String selection,
+    private int updateBookmarks(Uri uri, ContentValues values, String selection,
             String[] selectionArgs) {
         trace("Updating bookmarks on URI: " + uri);
 
         final String[] bookmarksProjection = new String[] {
                 Bookmarks._ID, // 0
         };
 
         if (!values.containsKey(Bookmarks.DATE_MODIFIED)) {
@@ -993,17 +987,17 @@ public class BrowserProvider extends Sha
         } finally {
             cursor.close();
         }
 
         beginWrite(db);
         return db.update(TABLE_BOOKMARKS, values, inClause, null);
     }
 
-    long insertHistory(Uri uri, ContentValues values) {
+    private long insertHistory(Uri uri, ContentValues values) {
         final long now = System.currentTimeMillis();
         values.put(History.DATE_CREATED, now);
         values.put(History.DATE_MODIFIED, now);
 
         // Generate GUID for new history entry. Don't override specified GUIDs.
         if (!values.containsKey(History.GUID)) {
           values.put(History.GUID, Utils.generateGuid());
         }
@@ -1011,17 +1005,17 @@ public class BrowserProvider extends Sha
         String url = values.getAsString(History.URL);
 
         debug("Inserting history in database with URL: " + url);
         final SQLiteDatabase db = getWritableDatabase(uri);
         beginWrite(db);
         return db.insertOrThrow(TABLE_HISTORY, History.VISITS, values);
     }
 
-    int updateOrInsertHistory(Uri uri, ContentValues values, String selection,
+    private int updateOrInsertHistory(Uri uri, ContentValues values, String selection,
             String[] selectionArgs) {
         final int updated = updateHistory(uri, values, selection, selectionArgs);
         if (updated > 0) {
             return updated;
         }
 
         // Insert a new entry if necessary
         if (!values.containsKey(History.VISITS)) {
@@ -1033,17 +1027,17 @@ public class BrowserProvider extends Sha
 
         if (0 <= insertHistory(uri, values)) {
             return 1;
         }
 
         return 0;
     }
 
-    int updateHistory(Uri uri, ContentValues values, String selection,
+    private int updateHistory(Uri uri, ContentValues values, String selection,
             String[] selectionArgs) {
         trace("Updating history on URI: " + uri);
 
         int updated = 0;
 
         final String[] historyProjection = new String[] {
             History._ID,   // 0
             History.URL,   // 1
@@ -1090,23 +1084,21 @@ public class BrowserProvider extends Sha
                   History.URL + " = ?",
                   new String[] { pageUrl });
         db.update(TABLE_BOOKMARKS,
                   updateValues,
                   Bookmarks.URL + " = ?",
                   new String[] { pageUrl });
     }
 
-    long insertFavicon(Uri uri, ContentValues values) {
+    private long insertFavicon(Uri uri, ContentValues values) {
         return insertFavicon(getWritableDatabase(uri), values);
     }
 
-    long insertFavicon(SQLiteDatabase db, ContentValues values) {
-        // This method is a dupicate of BrowserDatabaseHelper.insertFavicon.
-        // If changes are needed, please update both
+    private long insertFavicon(SQLiteDatabase db, ContentValues values) {
         String faviconUrl = values.getAsString(Favicons.URL);
         String pageUrl = null;
 
         trace("Inserting favicon for URL: " + faviconUrl);
 
         DBUtils.stripEmptyByteArray(values, Favicons.DATA);
 
         // Extract the page URL from the ContentValues
@@ -1128,29 +1120,29 @@ public class BrowserProvider extends Sha
         final long faviconId = db.insertOrThrow(TABLE_FAVICONS, null, values);
 
         if (pageUrl != null) {
             updateFaviconIdsForUrl(db, pageUrl, faviconId);
         }
         return faviconId;
     }
 
-    int updateOrInsertFavicon(Uri uri, ContentValues values, String selection,
+    private int updateOrInsertFavicon(Uri uri, ContentValues values, String selection,
             String[] selectionArgs) {
         return updateFavicon(uri, values, selection, selectionArgs,
                 true /* insert if needed */);
     }
 
-    int updateExistingFavicon(Uri uri, ContentValues values, String selection,
+    private int updateExistingFavicon(Uri uri, ContentValues values, String selection,
             String[] selectionArgs) {
         return updateFavicon(uri, values, selection, selectionArgs,
                 false /* only update, no insert */);
     }
 
-    int updateFavicon(Uri uri, ContentValues values, String selection,
+    private int updateFavicon(Uri uri, ContentValues values, String selection,
             String[] selectionArgs, boolean insertIfNeeded) {
         String faviconUrl = values.getAsString(Favicons.URL);
         String pageUrl = null;
         int updated = 0;
         Long faviconId = null;
         long now = System.currentTimeMillis();
 
         trace("Updating favicon for URL: " + faviconUrl);
@@ -1253,17 +1245,17 @@ public class BrowserProvider extends Sha
     }
 
     /**
      * This method does not create a new transaction. Its first operation is
      * guaranteed to be a write, which in the case of a new enclosing
      * transaction will guarantee that a read does not need to be upgraded to
      * a write.
      */
-    int deleteHistory(Uri uri, String selection, String[] selectionArgs) {
+    private int deleteHistory(Uri uri, String selection, String[] selectionArgs) {
         debug("Deleting history entry for URI: " + uri);
 
         final SQLiteDatabase db = getWritableDatabase(uri);
 
         if (isCallerSync(uri)) {
             return db.delete(TABLE_HISTORY, selection, selectionArgs);
         }
 
@@ -1291,17 +1283,17 @@ public class BrowserProvider extends Sha
             cleanUpSomeDeletedRecords(uri, TABLE_HISTORY);
         } catch (Exception e) {
             // We don't care.
             Log.e(LOGTAG, "Unable to clean up deleted history records: ", e);
         }
         return updated;
     }
 
-    int deleteBookmarks(Uri uri, String selection, String[] selectionArgs) {
+    private int deleteBookmarks(Uri uri, String selection, String[] selectionArgs) {
         debug("Deleting bookmarks for URI: " + uri);
 
         final SQLiteDatabase db = getWritableDatabase(uri);
 
         if (isCallerSync(uri)) {
             beginWrite(db);
             return db.delete(TABLE_BOOKMARKS, selection, selectionArgs);
         }
@@ -1320,33 +1312,33 @@ public class BrowserProvider extends Sha
             cleanUpSomeDeletedRecords(uri, TABLE_BOOKMARKS);
         } catch (Exception e) {
             // We don't care.
             Log.e(LOGTAG, "Unable to clean up deleted bookmark records: ", e);
         }
         return updated;
     }
 
-    int deleteFavicons(Uri uri, String selection, String[] selectionArgs) {
+    private int deleteFavicons(Uri uri, String selection, String[] selectionArgs) {
         debug("Deleting favicons for URI: " + uri);
 
         final SQLiteDatabase db = getWritableDatabase(uri);
 
         return db.delete(TABLE_FAVICONS, selection, selectionArgs);
     }
 
-    int deleteThumbnails(Uri uri, String selection, String[] selectionArgs) {
+    private int deleteThumbnails(Uri uri, String selection, String[] selectionArgs) {
         debug("Deleting thumbnails for URI: " + uri);
 
         final SQLiteDatabase db = getWritableDatabase(uri);
 
         return db.delete(TABLE_THUMBNAILS, selection, selectionArgs);
     }
 
-    int deleteUnusedImages(Uri uri) {
+    private int deleteUnusedImages(Uri uri) {
         debug("Deleting all unused favicons and thumbnails for URI: " + uri);
 
         String faviconSelection = Favicons._ID + " NOT IN "
                 + "(SELECT " + History.FAVICON_ID
                 + " FROM " + TABLE_HISTORY
                 + " WHERE " + History.IS_DELETED + " = 0"
                 + " AND " + History.FAVICON_ID + " IS NOT NULL"
                 + " UNION ALL SELECT " + Bookmarks.FAVICON_ID
--- a/mobile/android/base/db/LocalBrowserDB.java
+++ b/mobile/android/base/db/LocalBrowserDB.java
@@ -1,37 +1,53 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko.db;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
 import org.mozilla.gecko.AboutPages;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.db.BrowserContract.Combined;
 import org.mozilla.gecko.db.BrowserContract.ExpirePriority;
 import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
 import org.mozilla.gecko.db.BrowserContract.Favicons;
 import org.mozilla.gecko.db.BrowserContract.History;
 import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
 import org.mozilla.gecko.db.BrowserContract.SyncColumns;
 import org.mozilla.gecko.db.BrowserContract.Thumbnails;
 import org.mozilla.gecko.db.BrowserContract.URLColumns;
+import org.mozilla.gecko.distribution.Distribution;
 import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
 import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
+import org.mozilla.gecko.gfx.BitmapUtils;
+import org.mozilla.gecko.sync.Utils;
+import org.mozilla.gecko.util.GeckoJarReader;
 
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.CursorWrapper;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.net.Uri;
 import android.provider.Browser;
 import android.text.TextUtils;
@@ -57,17 +73,16 @@ public class LocalBrowserDB implements B
     private Boolean mDesktopBookmarksExist;
 
     private final Uri mBookmarksUriWithProfile;
     private final Uri mParentsUriWithProfile;
     private final Uri mFlagsUriWithProfile;
     private final Uri mHistoryUriWithProfile;
     private final Uri mHistoryExpireUriWithProfile;
     private final Uri mCombinedUriWithProfile;
-    private final Uri mDeletedHistoryUriWithProfile;
     private final Uri mUpdateHistoryUriWithProfile;
     private final Uri mFaviconsUriWithProfile;
     private final Uri mThumbnailsUriWithProfile;
     private final Uri mReadingListUriWithProfile;
 
     private static final String[] DEFAULT_BOOKMARK_COLUMNS =
             new String[] { Bookmarks._ID,
                            Bookmarks.GUID,
@@ -86,24 +101,291 @@ public class LocalBrowserDB implements B
         mFlagsUriWithProfile = appendProfile(Bookmarks.FLAGS_URI);
         mHistoryUriWithProfile = appendProfile(History.CONTENT_URI);
         mHistoryExpireUriWithProfile = appendProfile(History.CONTENT_OLD_URI);
         mCombinedUriWithProfile = appendProfile(Combined.CONTENT_URI);
         mFaviconsUriWithProfile = appendProfile(Favicons.CONTENT_URI);
         mThumbnailsUriWithProfile = appendProfile(Thumbnails.CONTENT_URI);
         mReadingListUriWithProfile = appendProfile(ReadingListItems.CONTENT_URI);
 
-        mDeletedHistoryUriWithProfile = mHistoryUriWithProfile.buildUpon().
-            appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1").build();
-
         mUpdateHistoryUriWithProfile = mHistoryUriWithProfile.buildUpon().
             appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").
             appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
     }
 
+    /**
+     * Add default bookmarks to the database.
+     * Takes an offset; returns a new offset.
+     */
+    @Override
+    public int addDefaultBookmarks(Context context, ContentResolver cr, final int offset) {
+        long folderId = getFolderIdFromGuid(cr, Bookmarks.MOBILE_FOLDER_GUID);
+        if (folderId == -1L) {
+            Log.e(LOGTAG, "No mobile folder: cannot add default bookmarks.");
+            return offset;
+        }
+
+        // Use reflection to walk the set of bookmark defaults.
+        // This is horrible.
+        final Class<?> stringsClass = R.string.class;
+        final Field[] fields = stringsClass.getFields();
+        final Pattern p = Pattern.compile("^bookmarkdefaults_title_");
+
+        int pos = offset;
+        final long now = System.currentTimeMillis();
+
+        final ArrayList<ContentValues> bookmarkValues = new ArrayList<ContentValues>();
+        final ArrayList<ContentValues> faviconValues = new ArrayList<ContentValues>();
+        for (int i = 0; i < fields.length; i++) {
+            final String name = fields[i].getName();
+            final Matcher m = p.matcher(name);
+            if (!m.find()) {
+                continue;
+            }
+
+            try {
+                final int titleid = fields[i].getInt(null);
+                final String title = context.getString(titleid);
+
+                final Field urlField = stringsClass.getField(name.replace("_title_", "_url_"));
+                final int urlId = urlField.getInt(null);
+                final String url = context.getString(urlId);
+
+                bookmarkValues.add(createBookmark(now, title, url, pos++, folderId));
+
+                Bitmap icon = getDefaultFaviconFromPath(context, name);
+                if (icon == null) {
+                    icon = getDefaultFaviconFromDrawable(context, name);
+                }
+                if (icon == null) {
+                    continue;
+                }
+
+                final ContentValues iconValue = createFavicon(url, icon);
+                if (iconValue != null) {
+                    faviconValues.add(iconValue);
+                }
+            } catch (IllegalAccessException e) {
+                Log.wtf(LOGTAG, "Reflection failure.", e);
+            } catch (IllegalArgumentException e) {
+                Log.wtf(LOGTAG, "Reflection failure.", e);
+            } catch (NoSuchFieldException e) {
+                Log.wtf(LOGTAG, "Reflection failure.", e);
+            }
+        }
+
+        if (!faviconValues.isEmpty()) {
+            try {
+                cr.bulkInsert(mFaviconsUriWithProfile, faviconValues.toArray(new ContentValues[faviconValues.size()]));
+            } catch (Exception e) {
+                Log.e(LOGTAG, "Error bulk-inserting default favicons.", e);
+            }
+        }
+
+        if (!bookmarkValues.isEmpty()) {
+            try {
+                final int inserted = cr.bulkInsert(mBookmarksUriWithProfile, bookmarkValues.toArray(new ContentValues[bookmarkValues.size()]));
+                return offset + inserted;
+            } catch (Exception e) {
+                Log.e(LOGTAG, "Error bulk-inserting default bookmarks.", e);
+            }
+        }
+
+        return offset;
+    }
+
+    /**
+     * Add bookmarks from the provided distribution.
+     * Takes an offset; returns a new offset.
+     */
+    @Override
+    public int addDistributionBookmarks(ContentResolver cr, Distribution distribution, int offset) {
+        if (!distribution.exists()) {
+            Log.d(LOGTAG, "No distribution from which to add bookmarks.");
+            return offset;
+        }
+
+        final JSONArray bookmarks = distribution.getBookmarks();
+        if (bookmarks == null) {
+            Log.d(LOGTAG, "No distribution bookmarks.");
+            return offset;
+        }
+
+        long folderId = getFolderIdFromGuid(cr, Bookmarks.MOBILE_FOLDER_GUID);
+        if (folderId == -1L) {
+            Log.e(LOGTAG, "No mobile folder: cannot add distribution bookmarks.");
+            return offset;
+        }
+
+        final Locale locale = Locale.getDefault();
+        final long now = System.currentTimeMillis();
+        int mobilePos = offset;
+        int pinnedPos = 0;        // Assume nobody has pinned anything yet.
+
+        final ArrayList<ContentValues> bookmarkValues = new ArrayList<ContentValues>();
+        final ArrayList<ContentValues> faviconValues = new ArrayList<ContentValues>();
+        for (int i = 0; i < bookmarks.length(); i++) {
+            try {
+                final JSONObject bookmark = bookmarks.getJSONObject(i);
+
+                final String title = getLocalizedProperty(bookmark, "title", locale);
+                final String url = getLocalizedProperty(bookmark, "url", locale);
+                final long parent;
+                final int pos;
+                if (bookmark.has("pinned")) {
+                    parent = Bookmarks.FIXED_PINNED_LIST_ID;
+                    pos = pinnedPos++;
+                } else {
+                    parent = folderId;
+                    pos = mobilePos++;
+                }
+
+                bookmarkValues.add(createBookmark(now, title, url, pos, parent));
+
+                // Return early if there is no icon for this bookmark.
+                if (!bookmark.has("icon")) {
+                    continue;
+                }
+
+                try {
+                    final String iconData = bookmark.getString("icon");
+                    final Bitmap icon = BitmapUtils.getBitmapFromDataURI(iconData);
+                    if (icon == null) {
+                        continue;
+                    }
+                    final ContentValues iconValue = createFavicon(url, icon);
+                    if (iconValue != null) {
+                        faviconValues.add(iconValue);
+                    }
+                } catch (JSONException e) {
+                    Log.e(LOGTAG, "Error creating distribution bookmark icon.", e);
+                }
+            } catch (JSONException e) {
+                Log.e(LOGTAG, "Error creating distribution bookmark.", e);
+            }
+        }
+
+        if (!faviconValues.isEmpty()) {
+            try {
+                cr.bulkInsert(mFaviconsUriWithProfile, faviconValues.toArray(new ContentValues[faviconValues.size()]));
+            } catch (Exception e) {
+                Log.e(LOGTAG, "Error bulk-inserting distribution favicons.", e);
+            }
+        }
+
+        if (!bookmarkValues.isEmpty()) {
+            try {
+                final int inserted = cr.bulkInsert(mBookmarksUriWithProfile, bookmarkValues.toArray(new ContentValues[bookmarkValues.size()]));
+                return offset + inserted;
+            } catch (Exception e) {
+                Log.e(LOGTAG, "Error bulk-inserting distribution bookmarks.", e);
+            }
+        }
+
+        return offset;
+    }
+
+    private static ContentValues createBookmark(final long timestamp, final String title, final String url, final int pos, final long parent) {
+        final ContentValues v = new ContentValues();
+
+        v.put(Bookmarks.DATE_CREATED, timestamp);
+        v.put(Bookmarks.DATE_MODIFIED, timestamp);
+        v.put(Bookmarks.GUID, Utils.generateGuid());
+
+        v.put(Bookmarks.PARENT, parent);
+        v.put(Bookmarks.POSITION, pos);
+        v.put(Bookmarks.TITLE, title);
+        v.put(Bookmarks.URL, url);
+        return v;
+    }
+
+    private static ContentValues createFavicon(final String url, final Bitmap icon) {
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+
+        ContentValues iconValues = new ContentValues();
+        iconValues.put(Favicons.PAGE_URL, url);
+
+        byte[] data = null;
+        if (icon.compress(Bitmap.CompressFormat.PNG, 100, stream)) {
+            data = stream.toByteArray();
+        } else {
+            Log.w(LOGTAG, "Favicon compression failed.");
+            return null;
+        }
+
+        iconValues.put(Favicons.DATA, data);
+        return iconValues;
+    }
+
+    private static String getLocalizedProperty(final JSONObject bookmark, final String property, final Locale locale) throws JSONException {
+        // Try the full locale.
+        final String fullLocale = property + "." + locale.toString();
+        if (bookmark.has(fullLocale)) {
+            return bookmark.getString(fullLocale);
+        }
+
+        // Try without a variant.
+        if (!TextUtils.isEmpty(locale.getVariant())) {
+            String noVariant = fullLocale.substring(0, fullLocale.lastIndexOf("_"));
+            if (bookmark.has(noVariant)) {
+                return bookmark.getString(noVariant);
+            }
+        }
+
+        // Try just the language.
+        String lang = property + "." + locale.getLanguage();
+        if (bookmark.has(lang)) {
+            return bookmark.getString(lang);
+        }
+
+        // Default to the non-localized property name.
+        return bookmark.getString(property);
+    }
+
+    private static Bitmap getDefaultFaviconFromPath(Context context, String name) {
+        Class<?> stringClass = R.string.class;
+        try {
+            // Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_*
+            Field faviconField = stringClass.getField(name.replace("_title_", "_favicon_"));
+            if (faviconField == null) {
+                return null;
+            }
+            int faviconId = faviconField.getInt(null);
+            String path = context.getString(faviconId);
+
+            String apkPath = context.getPackageResourcePath();
+            File apkFile = new File(apkPath);
+            String bitmapPath = "jar:jar:" + apkFile.toURI() + "!/" + AppConstants.OMNIJAR_NAME + "!/" + path;
+            return GeckoJarReader.getBitmap(context.getResources(), bitmapPath);
+        } catch (java.lang.IllegalAccessException ex) {
+            Log.e(LOGTAG, "[Path] Can't create favicon " + name, ex);
+        } catch (java.lang.NoSuchFieldException ex) {
+            // If the field does not exist, that means we intend to load via a drawable.
+        }
+        return null;
+    }
+
+    private static Bitmap getDefaultFaviconFromDrawable(Context context, String name) {
+        Class<?> drawablesClass = R.drawable.class;
+        try {
+            // Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_*
+            Field faviconField = drawablesClass.getField(name.replace("_title_", "_favicon_"));
+            if (faviconField == null) {
+                return null;
+            }
+            int faviconId = faviconField.getInt(null);
+            return BitmapUtils.decodeResource(context, faviconId);
+        } catch (java.lang.IllegalAccessException ex) {
+            Log.e(LOGTAG, "[Drawable] Can't create favicon " + name, ex);
+        } catch (java.lang.NoSuchFieldException ex) {
+            Log.wtf(LOGTAG, "No field, and presumably no drawable, for " + name);
+        }
+        return null;
+    }
+
     // Invalidate cached data
     @Override
     public void invalidateCachedState() {
         mDesktopBookmarksExist = null;
     }
 
     private Uri historyUriWithLimit(int limit) {
         return mHistoryUriWithProfile.buildUpon().appendQueryParameter(BrowserContract.PARAM_LIMIT,
@@ -363,17 +645,17 @@ public class LocalBrowserDB implements B
     public void removeHistoryEntry(ContentResolver cr, int id) {
         cr.delete(mHistoryUriWithProfile,
                   History._ID + " = ?",
                   new String[] { String.valueOf(id) });
     }
 
     @Override
     public void removeHistoryEntry(ContentResolver cr, String url) {
-        int deleted = cr.delete(mHistoryUriWithProfile,
+        cr.delete(mHistoryUriWithProfile,
                   History.URL + " = ?",
                   new String[] { url });
     }
 
     @Override
     public void clearHistory(ContentResolver cr) {
         cr.delete(mHistoryUriWithProfile, null, null);
     }
@@ -572,39 +854,38 @@ public class LocalBrowserDB implements B
         } finally {
             if (c != null)
                 c.close();
         }
 
         return null;
     }
 
-    private synchronized long getFolderIdFromGuid(ContentResolver cr, String guid) {
-        if (mFolderIdMap.containsKey(guid))
+    private synchronized long getFolderIdFromGuid(final ContentResolver cr, final String guid) {
+        if (mFolderIdMap.containsKey(guid)) {
             return mFolderIdMap.get(guid);
-
-        long folderId = -1;
-        Cursor c = null;
-
-        try {
-            c = cr.query(mBookmarksUriWithProfile,
-                         new String[] { Bookmarks._ID },
-                         Bookmarks.GUID + " = ?",
-                         new String[] { guid },
-                         null);
-
-            if (c.moveToFirst())
-                folderId = c.getLong(c.getColumnIndexOrThrow(Bookmarks._ID));
-        } finally {
-            if (c != null)
-                c.close();
         }
 
-        mFolderIdMap.put(guid, folderId);
-        return folderId;
+        final Cursor c = cr.query(mBookmarksUriWithProfile,
+                                  new String[] { Bookmarks._ID },
+                                  Bookmarks.GUID + " = ?",
+                                  new String[] { guid },
+                                  null);
+        try {
+            final int col = c.getColumnIndexOrThrow(Bookmarks._ID);
+            if (!c.moveToFirst() || c.isNull(col)) {
+                return -1;
+            }
+
+            final long id = c.getLong(col);
+            mFolderIdMap.put(guid, id);
+            return id;
+        } finally {
+            c.close();
+        }
     }
 
     /**
      * Find parents of records that match the provided criteria, and bump their
      * modified timestamp.
      */
     protected void bumpParents(ContentResolver cr, String param, String value) {
         ContentValues values = new ContentValues();
--- a/mobile/android/base/home/HomeListView.java
+++ b/mobile/android/base/home/HomeListView.java
@@ -59,17 +59,17 @@ public class HomeListView extends ListVi
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         final Drawable divider = getDivider();
         if (mShowTopDivider && divider != null) {
             final int dividerHeight = getDividerHeight();
             final View view = new View(getContext());
-            view.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, dividerHeight));
+            view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, dividerHeight));
             addHeaderView(view);
         }
     }
 
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
--- a/mobile/android/base/home/TabMenuStrip.java
+++ b/mobile/android/base/home/TabMenuStrip.java
@@ -39,17 +39,17 @@ public class TabMenuStrip extends Horizo
         super(context, attrs);
 
         // Disable the scroll bar.
         setHorizontalScrollBarEnabled(false);
 
         titleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
 
         layout = new TabMenuStripLayout(context, attrs);
-        addView(layout, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
+        addView(layout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
     }
 
     @Override
     public void onAddPagerView(String title) {
         layout.onAddPagerView(title);
     }
 
     @Override
--- a/mobile/android/base/menu/GeckoMenu.java
+++ b/mobile/android/base/menu/GeckoMenu.java
@@ -120,18 +120,18 @@ public class GeckoMenu extends ListView
 
     public GeckoMenu(Context context, AttributeSet attrs) {
         this(context, attrs, R.attr.geckoMenuListViewStyle);
     }
 
     public GeckoMenu(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
-                                         LayoutParams.FILL_PARENT));
+        setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                                         LayoutParams.MATCH_PARENT));
 
         // Attach an adapter.
         mAdapter = new MenuItemsAdapter();
         setAdapter(mAdapter);
         setOnItemClickListener(this);
 
         mShowIcons = false;
         mItems = new ArrayList<GeckoMenuItem>();
--- a/mobile/android/base/prompts/PromptInput.java
+++ b/mobile/android/base/prompts/PromptInput.java
@@ -136,17 +136,17 @@ public class PromptInput {
 
         public CheckboxInput(JSONObject obj) {
             super(obj);
             mChecked = obj.optBoolean("checked");
         }
 
         public View getView(Context context) throws UnsupportedOperationException {
             CheckBox checkbox = new CheckBox(context);
-            checkbox.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
+            checkbox.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
             checkbox.setText(mLabel);
             checkbox.setChecked(mChecked);
             mView = (View)checkbox;
             return mView;
         }
 
         @Override
         public Object getValue() {
--- a/mobile/android/base/resources/layout-large-land-v11/home_history_list.xml
+++ b/mobile/android/base/resources/layout-large-land-v11/home_history_list.xml
@@ -2,19 +2,19 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <ViewStub android:id="@+id/home_empty_view_stub"
               android:layout="@layout/home_empty_panel"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"/>
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"/>
 
     <org.mozilla.gecko.home.HomeListView
             android:id="@+id/list"
             style="@style/Widget.Home.HistoryListView"
-            android:layout_width="fill_parent"
+            android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1"/>
 
 </merge>
--- a/mobile/android/base/resources/layout-large-land-v11/home_history_panel.xml
+++ b/mobile/android/base/resources/layout-large-land-v11/home_history_panel.xml
@@ -1,24 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               xmlns:gecko="http://schemas.android.com/apk/res-auto"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent">
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
 
     <org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_icon_widget"
                                             style="@style/Widget.Home.HistoryTabWidget"
                                             android:layout_width="@dimen/history_tab_widget_width"
                                             android:layout_height="@dimen/history_tab_widget_height"
                                             android:orientation="vertical"
                                             android:layout="@layout/home_history_tabs_indicator"
                                             gecko:display="text"/>
 
     <FrameLayout android:id="@+id/history_panel_container"
                  android:layout_width="0dp"
-                 android:layout_height="fill_parent"
+                 android:layout_height="match_parent"
                  android:layout_weight="1" />
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout-large-land-v11/home_history_tabs_indicator.xml
+++ b/mobile/android/base/resources/layout-large-land-v11/home_history_tabs_indicator.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
           style="@style/Widget.Home.HistoryTabIndicator"
-          android:layout_width="fill_parent"
+          android:layout_width="match_parent"
           android:layout_height="@dimen/history_tab_indicator_height"
           android:background="@drawable/home_history_tabs_indicator"/>
--- a/mobile/android/base/resources/layout-large-land-v11/tabs_panel.xml
+++ b/mobile/android/base/resources/layout-large-land-v11/tabs_panel.xml
@@ -2,45 +2,45 @@
 <!-- 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/. -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:gecko="http://schemas.android.com/apk/res-auto">
 
     <RelativeLayout android:id="@+id/tabs_panel_header"
-                    android:layout_width="fill_parent"
+                    android:layout_width="match_parent"
                     android:layout_height="@dimen/browser_toolbar_height">
 
         <view class="org.mozilla.gecko.tabspanel.TabsPanel$TabsPanelToolbar"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
               android:background="@color/background_tabs">
 
             <include layout="@layout/tabs_panel_header"/>
 
         </view>
 
-        <View android:layout_width="fill_parent"
+        <View android:layout_width="match_parent"
               android:layout_height="2dp"
               android:layout_alignParentBottom="true"
               android:background="#1A000000"/>
 
     </RelativeLayout>
 
     <view class="org.mozilla.gecko.tabspanel.TabsPanel$TabsListContainer"
           android:id="@+id/tabs_container"
-          android:layout_width="fill_parent"
+          android:layout_width="match_parent"
           android:layout_height="0dip"
           android:layout_weight="1.0">
 
         <org.mozilla.gecko.tabspanel.TabsTray android:id="@+id/normal_tabs"
                                               style="@style/TabsList"
-                                              android:layout_width="fill_parent"
-                                              android:layout_height="fill_parent"
+                                              android:layout_width="match_parent"
+                                              android:layout_height="match_parent"
                                               android:choiceMode="singleChoice"
                                               android:visibility="gone"
                                               gecko:tabs="tabs_normal"/>
 
         <org.mozilla.gecko.tabspanel.PrivateTabsPanel
                 android:id="@+id/private_tabs_panel"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
@@ -50,28 +50,28 @@
                 android:id="@+id/remote_tabs"
                 android:layout_height="match_parent"
                 android:layout_width="match_parent"
                 android:visibility="gone"/>
 
     </view>
 
     <RelativeLayout android:id="@+id/tabs_panel_footer"
-                    android:layout_width="fill_parent"
+                    android:layout_width="match_parent"
                     android:layout_height="@dimen/browser_toolbar_height">
 
         <view class="org.mozilla.gecko.tabspanel.TabsPanel$TabsPanelToolbar"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
               android:background="@color/background_tabs">
 
             <include layout="@layout/tabs_panel_footer"/>
 
         </view>
 
-        <View android:layout_width="fill_parent"
+        <View android:layout_width="match_parent"
               android:layout_height="2dp"
               android:layout_alignParentTop="true"
               android:background="#1A000000"/>
 
     </RelativeLayout>
 
 </merge>
--- a/mobile/android/base/resources/layout-large-land-v11/tabs_panel_header.xml
+++ b/mobile/android/base/resources/layout-large-land-v11/tabs_panel_header.xml
@@ -2,14 +2,14 @@
 <!-- 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/. -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_widget"
                                             android:layout_width="wrap_content"
-                                            android:layout_height="fill_parent"
+                                            android:layout_height="match_parent"
                                             android:tabStripEnabled="false"
                                             android:divider="@drawable/tab_indicator_divider"
                                             android:layout="@layout/tabs_panel_indicator"/>
 
 </merge>
--- a/mobile/android/base/resources/layout-large-v11/browser_toolbar.xml
+++ b/mobile/android/base/resources/layout-large-v11/browser_toolbar.xml
@@ -29,18 +29,18 @@
                         android:layout_marginLeft="12dip"
                         android:layout_marginRight="48dip"
                         android:layout_marginTop="16dp"
                         android:layout_alignLeft="@id/tabs"/>
 
     <!-- In editing mode, the toolbar shrinks by changing to
          dynamically constructed LayoutParams. -->
     <ImageView android:id="@+id/url_bar_entry"
-               android:layout_width="fill_parent"
-               android:layout_height="fill_parent"
+               android:layout_width="match_parent"
+               android:layout_height="match_parent"
                android:layout_toRightOf="@id/tabs"
                android:layout_toLeftOf="@id/menu_items"
                android:layout_marginLeft="-18dp"
                android:layout_marginTop="7dp"
                android:layout_marginBottom="7dp"
                android:duplicateParentState="true"
                android:clickable="false"
                android:focusable="false"
@@ -73,17 +73,17 @@
 
     <org.mozilla.gecko.toolbar.ToolbarDisplayLayout android:id="@+id/display_layout"
                   style="@style/UrlBar.Button.Container"
                   android:layout_toRightOf="@id/back"
                   android:layout_toLeftOf="@id/menu_items"/>
 
     <LinearLayout android:id="@+id/menu_items"
                   android:layout_width="wrap_content"
-                  android:layout_height="fill_parent"
+                  android:layout_height="match_parent"
                   android:layout_marginLeft="3dp"
                   android:orientation="horizontal"
                   android:layout_toLeftOf="@id/menu"
                   android:layout_alignWithParentIfMissing="true"/>
 
     <org.mozilla.gecko.widget.ThemedImageButton android:id="@+id/menu"
                                                 style="@style/UrlBar.ImageButton"
                                                 android:layout_width="56dip"
@@ -96,17 +96,17 @@
                                               style="@style/UrlBar.ImageButton"
                                               android:layout_alignLeft="@id/menu"
                                               android:layout_alignRight="@id/menu"
                                               android:gravity="center_vertical"
                                               android:src="@drawable/menu_level"
                                               android:visibility="gone"/>
 
     <ImageView android:id="@+id/shadow"
-               android:layout_width="fill_parent"
+               android:layout_width="match_parent"
                android:layout_height="2dp"
                android:layout_alignParentBottom="true"
                android:background="@color/url_bar_shadow"
                android:contentDescription="@null"/>
 
     <!-- We draw after the menu items so when they are hidden, the cancel button,
          which is thus drawn on top, may be pressed. -->
     <org.mozilla.gecko.widget.ThemedImageView
--- a/mobile/android/base/resources/layout-large-v11/home_pager.xml
+++ b/mobile/android/base/resources/layout-large-v11/home_pager.xml
@@ -4,19 +4,19 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!-- This file is used to include the home pager in gecko app
      layout based on screen size -->
 
 <org.mozilla.gecko.home.HomePager xmlns:android="http://schemas.android.com/apk/res/android"
                                   xmlns:gecko="http://schemas.android.com/apk/res-auto"
                                   android:id="@+id/home_pager"
-                                  android:layout_width="fill_parent"
-                                  android:layout_height="fill_parent"
+                                  android:layout_width="match_parent"
+                                  android:layout_height="match_parent"
                                   android:background="@android:color/white">
 
-    <org.mozilla.gecko.home.TabMenuStrip android:layout_width="fill_parent"
+    <org.mozilla.gecko.home.TabMenuStrip android:layout_width="match_parent"
                                          android:layout_height="32dip"
                                          android:background="@color/background_light"
                                          android:layout_gravity="top"
                                          gecko:strip="@drawable/home_tab_menu_strip"/>
 
 </org.mozilla.gecko.home.HomePager>
--- a/mobile/android/base/resources/layout-xlarge-v11/font_size_preference.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/font_size_preference.xml
@@ -1,52 +1,52 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this file,
    - You can obtain one at http://mozilla.org/MPL/2.0/.  -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
                 android:orientation="vertical"> 
 
     <ScrollView android:id="@+id/scrolling_container"
-                android:layout_width="fill_parent"
+                android:layout_width="match_parent"
                 android:layout_height="350dp"
                 android:layout_margin="8dp"
                 android:padding="8dp"
                 android:scrollbars="vertical"
                 android:scrollbarStyle="outsideOverlay"
                 android:fadeScrollbars="true"
                 android:requiresFadingEdge="vertical">
 
             <TextView android:id="@+id/preview"
-                      android:layout_width="fill_parent"
+                      android:layout_width="match_parent"
                       android:layout_height="wrap_content"
                       android:text="@string/pref_font_size_preview_text"
                       android:textColor="#ff000000"/>
 
     </ScrollView>
 
     <LinearLayout android:id="@+id/button_container"
-                  android:layout_width="fill_parent"
+                  android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:layout_marginLeft="4dp"
                   android:layout_marginRight="4dp"
                   android:orientation="horizontal">
 
         <Button android:id="@+id/decrease_preview_font_button"
                 android:layout_width="0dp"
-                android:layout_height="fill_parent"
+                android:layout_height="match_parent"
                 android:layout_weight="1"
                 android:text="@string/pref_font_size_adjust_char"
                 android:textSize="8sp"/>
 
         <Button android:id="@+id/increase_preview_font_button"
                 android:layout_width="0dp"
-                android:layout_height="fill_parent"
+                android:layout_height="match_parent"
                 android:layout_weight="1"
                 android:text="@string/pref_font_size_adjust_char"
                 android:textSize="16sp"/>
 
     </LinearLayout>
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout-xlarge-v11/home_history_list.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/home_history_list.xml
@@ -2,19 +2,19 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <ViewStub android:id="@+id/home_empty_view_stub"
               android:layout="@layout/home_empty_panel"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"/>
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"/>
 
     <org.mozilla.gecko.home.HomeListView
             android:id="@+id/list"
             style="@style/Widget.Home.HistoryListView"
-            android:layout_width="fill_parent"
+            android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1"/>
 
 </merge>
--- a/mobile/android/base/resources/layout-xlarge-v11/home_history_panel.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/home_history_panel.xml
@@ -1,24 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               xmlns:gecko="http://schemas.android.com/apk/res-auto"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent">
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
 
     <org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_icon_widget"
                                             style="@style/Widget.Home.HistoryTabWidget"
                                             android:layout_width="@dimen/history_tab_widget_width"
                                             android:layout_height="@dimen/history_tab_widget_height"
                                             android:orientation="vertical"
                                             android:layout="@layout/home_history_tabs_indicator"
                                             gecko:display="text"/>
 
     <FrameLayout android:id="@+id/history_panel_container"
                  android:layout_width="0dp"
-                 android:layout_height="fill_parent"
+                 android:layout_height="match_parent"
                  android:layout_weight="1" />
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout-xlarge-v11/home_history_tabs_indicator.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/home_history_tabs_indicator.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
           style="@style/Widget.Home.HistoryTabIndicator"
-          android:layout_width="fill_parent"
+          android:layout_width="match_parent"
           android:layout_height="@dimen/history_tab_indicator_height"
           android:background="@drawable/home_history_tabs_indicator"/>
--- a/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_child.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_child.xml
@@ -1,27 +1,27 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:background="@drawable/action_bar_button_inverse"
               android:gravity="center_vertical"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="@dimen/remote_tab_child_row_height"
               android:orientation="vertical"
               android:paddingLeft="2dp"
               android:paddingRight="2dp">
 
     <TextView android:id="@+id/tab"
               style="@style/TabRowTextAppearance"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:textSize="14sp"/>
 
     <TextView android:id="@+id/url"
               style="@style/TabRowTextAppearance.Url"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:textSize="12sp"/>
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_group.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_group.xml
@@ -1,30 +1,30 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:background="@android:color/transparent"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="@dimen/remote_tab_child_row_height"
               android:gravity="center_vertical"
               android:orientation="vertical"
               android:paddingLeft="2dp"
               android:paddingRight="2dp">
 
     <org.mozilla.gecko.widget.AllCapsTextView android:id="@+id/client"
                                               style="@style/TabRowTextAppearance"
-                                              android:layout_width="fill_parent"
+                                              android:layout_width="match_parent"
                                               android:layout_height="wrap_content"
                                               android:maxLines="2"
                                               android:singleLine="false"
                                               android:textSize="14sp"
                                               android:textStyle="bold" />
 
     <TextView android:id="@+id/last_synced"
               style="@style/TabRowTextAppearance.Url"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:textSize="12sp"/>
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout/actionbar.xml
+++ b/mobile/android/base/resources/layout/actionbar.xml
@@ -1,31 +1,31 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <Button android:id="@+id/actionmode_title"
-            android:layout_height="fill_parent"
+            android:layout_height="match_parent"
             android:layout_width="wrap_content"
             style="@style/GeckoActionBar.Title"/>
 
     <!-- Draw a separator to the left of the title -->
-    <View android:layout_height="fill_parent"
+    <View android:layout_height="match_parent"
           android:layout_width="1dp"
           android:layout_marginTop="10dp"
           android:layout_marginBottom="10dp"
           android:background="@color/text_color_secondary_inverse"/>
 
     <LinearLayout android:id="@+id/actionbar_buttons"
-                  android:layout_height="fill_parent"
+                  android:layout_height="match_parent"
                   android:layout_width="0dip"
                   android:layout_weight="1"
                   style="@style/GeckoActionBar.Buttons"/>
 
     <ImageButton android:id="@+id/actionbar_menu"
-                 android:layout_height="fill_parent"
+                 android:layout_height="match_parent"
                  android:layout_width="@dimen/browser_toolbar_icon_width"
                  style="@style/GeckoActionBar.Button.MenuButton"/>
 
 </merge>
--- a/mobile/android/base/resources/layout/arrow_popup.xml
+++ b/mobile/android/base/resources/layout/arrow_popup.xml
@@ -1,30 +1,31 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="?attr/arrowPopupWidth"
-                android:layout_height="wrap_content">
+<view class="org.mozilla.gecko.widget.ArrowPopup$ArrowPopupLayout"
+      xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content">
 
     <ScrollView android:layout_width="?attr/arrowPopupWidth"
                 android:layout_height="wrap_content"
                 android:layout_alignParentTop="true"
                 android:background="@drawable/arrow_popup_bg">
 
         <LinearLayout android:id="@+id/content"
-                      android:layout_width="fill_parent"
+                      android:layout_width="match_parent"
                       android:layout_height="wrap_content"
                       android:orientation="vertical"/>
 
     </ScrollView>
 
     <ImageView android:id="@+id/arrow"
-               android:layout_width="@dimen/menu_popup_arrow_width"
+               android:layout_width="@dimen/arrow_popup_arrow_width"
                android:layout_height="12dip"
                android:layout_marginLeft="20dip"
                android:layout_alignParentTop="true"
                android:src="@drawable/menu_popup_arrow_top"
                android:scaleType="fitXY"/>
 
-</RelativeLayout>
+</view>
--- a/mobile/android/base/resources/layout/autocomplete_list.xml
+++ b/mobile/android/base/resources/layout/autocomplete_list.xml
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <ListView xmlns:android="http://schemas.android.com/apk/res/android"
           style="@android:style/Widget.Holo.ListView"
-          android:layout_width="fill_parent"
-          android:layout_height="fill_parent"
+          android:layout_width="match_parent"
+          android:layout_height="match_parent"
           android:background="@drawable/autocomplete_list_bg"
           android:cacheColorHint="#ffffff"/>
--- a/mobile/android/base/resources/layout/autocomplete_list_item.xml
+++ b/mobile/android/base/resources/layout/autocomplete_list_item.xml
@@ -1,14 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
-          android:layout_width="fill_parent"
+          android:layout_width="match_parent"
           android:layout_height="32dip"
           android:textAppearance="@style/TextAppearance.Medium"
           android:layout_gravity="center_vertical"
           android:paddingLeft="10dp"
           android:paddingRight="10dp"
           android:paddingTop="3dp"
           android:paddingBottom="3dp"/>
--- a/mobile/android/base/resources/layout/basic_color_picker_dialog.xml
+++ b/mobile/android/base/resources/layout/basic_color_picker_dialog.xml
@@ -1,21 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_height="wrap_content"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:orientation="vertical">
 
   <org.mozilla.gecko.widget.BasicColorPicker android:id="@+id/colorpicker"
                                              android:layout_height="0dip"
                                              android:layout_weight="1"
                                              android:drawSelectorOnTop="true"
                                              android:choiceMode="singleChoice"
                                              android:divider="@android:color/transparent"
                                              android:dividerHeight="0dip"
                                              android:listSelector="#22FFFFFF"
-                                             android:layout_width="fill_parent"/>
+                                             android:layout_width="match_parent"/>
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout/bookmark_edit.xml
+++ b/mobile/android/base/resources/layout/bookmark_edit.xml
@@ -1,34 +1,34 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:orientation="vertical"
-              android:layout_height="fill_parent">
+              android:layout_height="match_parent">
 
     <org.mozilla.gecko.widget.FloatingHintEditText
               android:id="@+id/edit_bookmark_name"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:singleLine="true"
               android:hint="@string/bookmark_edit_name"/>
 
     <org.mozilla.gecko.widget.FloatingHintEditText
               android:id="@+id/edit_bookmark_location"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:singleLine="true"
               android:hint="@string/bookmark_edit_location"
               android:inputType="textNoSuggestions"/>
 
     <org.mozilla.gecko.widget.FloatingHintEditText
               android:id="@+id/edit_bookmark_keyword"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:singleLine="true"
               android:hint="@string/bookmark_edit_keyword"/>
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout/bookmark_folder_row.xml
+++ b/mobile/android/base/resources/layout/bookmark_folder_row.xml
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <org.mozilla.gecko.home.BookmarkFolderView xmlns:android="http://schemas.android.com/apk/res/android"
                                            style="@style/Widget.BookmarkFolderView"
-                                           android:layout_width="fill_parent"
+                                           android:layout_width="match_parent"
                                            android:layout_height="@dimen/page_row_height"
                                            android:minHeight="@dimen/page_row_height"
                                            android:gravity="center_vertical"/>
--- a/mobile/android/base/resources/layout/bookmark_item_row.xml
+++ b/mobile/android/base/resources/layout/bookmark_item_row.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <org.mozilla.gecko.home.TwoLinePageRow xmlns:android="http://schemas.android.com/apk/res/android"
                                        style="@style/Widget.BookmarkItemView"
-                                       android:layout_width="fill_parent"
+                                       android:layout_width="match_parent"
                                        android:layout_height="@dimen/page_row_height"
                                        android:minHeight="@dimen/page_row_height"/>
--- a/mobile/android/base/resources/layout/browser_toolbar.xml
+++ b/mobile/android/base/resources/layout/browser_toolbar.xml
@@ -118,15 +118,15 @@
                   android:visibility="invisible"/>
 
     <org.mozilla.gecko.toolbar.ToolbarDisplayLayout android:id="@+id/display_layout"
                   style="@style/UrlBar.Button"
                   android:layout_toLeftOf="@id/tabs"
                   android:layout_marginRight="-24dp"/>
 
     <ImageView android:id="@+id/shadow"
-               android:layout_width="fill_parent"
+               android:layout_width="match_parent"
                android:layout_height="2dp"
                android:layout_alignParentBottom="true"
                android:background="@color/url_bar_shadow"
                android:contentDescription="@null"/>
 
 </merge>
--- a/mobile/android/base/resources/layout/doorhanger.xml
+++ b/mobile/android/base/resources/layout/doorhanger.xml
@@ -13,48 +13,48 @@
         <ImageView android:id="@+id/doorhanger_icon"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingRight="@dimen/doorhanger_padding"
                    android:visibility="gone"/>
 
         <TextView android:id="@+id/doorhanger_title"
                   android:focusable="true"
-                  android:layout_width="fill_parent"
+                  android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:textAppearance="?android:attr/textAppearanceMedium"
                   android:textColor="@color/doorhanger_text"
                   android:textColorLink="@color/doorhanger_link"/>
 
     </LinearLayout>
 
     <LinearLayout android:id="@+id/doorhanger_inputs"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:orientation="vertical"
               android:gravity="right"
               android:visibility="gone"/>
 
     <CheckBox android:id="@+id/doorhanger_checkbox"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:checked="true"
               android:textColor="@color/doorhanger_text"
               android:visibility="gone"/>
 
     <View android:id="@+id/divider_choices"
-          android:layout_width="fill_parent"
+          android:layout_width="match_parent"
           android:layout_height="1dp"
           android:visibility="gone"/>
 
     <LinearLayout android:id="@+id/doorhanger_choices"
-                  android:layout_width="fill_parent"
+                  android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:orientation="horizontal"
                   android:visibility="gone"/>
 
     <View android:id="@+id/divider_doorhanger"
-          android:layout_width="fill_parent"
+          android:layout_width="match_parent"
           android:layout_height="1dp"
           android:background="#FFFF9500"
           android:visibility="gone"/>
 
 </merge>
--- a/mobile/android/base/resources/layout/font_size_preference.xml
+++ b/mobile/android/base/resources/layout/font_size_preference.xml
@@ -1,54 +1,54 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this file,
    - You can obtain one at http://mozilla.org/MPL/2.0/.  -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent">
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
 
     <LinearLayout android:id="@+id/button_container"
-                  android:layout_width="fill_parent"
+                  android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:layout_marginLeft="4dp"
                   android:layout_marginRight="4dp"
                   android:layout_alignParentBottom="true"
                   android:layout_alignParentLeft="true"
                   android:orientation="horizontal">
 
         <Button android:id="@+id/decrease_preview_font_button"
                 android:layout_width="0dp"
-                android:layout_height="fill_parent"
+                android:layout_height="match_parent"
                 android:layout_weight="1"
                 android:text="@string/pref_font_size_adjust_char"
                 android:textSize="8sp"/>
 
         <Button android:id="@+id/increase_preview_font_button"
                 android:layout_width="0dp"
-                android:layout_height="fill_parent"
+                android:layout_height="match_parent"
                 android:layout_weight="1"
                 android:text="@string/pref_font_size_adjust_char"
                 android:textSize="16sp"/>
 
     </LinearLayout>
 
     <ScrollView android:id="@+id/scrolling_container"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
                 android:layout_above="@id/button_container"
                 android:layout_margin="8dp"
                 android:padding="8dp"
                 android:scrollbars="vertical"
                 android:scrollbarStyle="outsideOverlay"
                 android:fadeScrollbars="true"
                 android:requiresFadingEdge="vertical">
 
             <TextView android:id="@+id/preview"
-                      android:layout_width="fill_parent"
+                      android:layout_width="match_parent"
                       android:layout_height="wrap_content"
                       android:text="@string/pref_font_size_preview_text"
                       android:textColor="#ff000000"/>
 
     </ScrollView>
 
 </RelativeLayout>
--- a/mobile/android/base/resources/layout/fxaccount_account_verified.xml
+++ b/mobile/android/base/resources/layout/fxaccount_account_verified.xml
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
    This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/.
 -->
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fillViewport="true" >
 
     <LinearLayout style="@style/FxAccountMiddle" >
 
         <TextView
             style="@style/FxAccountHeaderItem"
             android:text="@string/fxaccount_account_verified_sub_header" >
         </TextView>
--- a/mobile/android/base/resources/layout/fxaccount_confirm_account.xml
+++ b/mobile/android/base/resources/layout/fxaccount_confirm_account.xml
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
    This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/.
 -->
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fillViewport="true" >
 
     <LinearLayout style="@style/FxAccountMiddle" >
 
         <LinearLayout style="@style/FxAccountSpacer" />
 
         <TextView
             style="@style/FxAccountHeaderItem"
--- a/mobile/android/base/resources/layout/fxaccount_create_account.xml
+++ b/mobile/android/base/resources/layout/fxaccount_create_account.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
    This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/.
 -->
 
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fillViewport="true" >
 
     <LinearLayout
         android:id="@+id/create_account_view"
         style="@style/FxAccountMiddle" >
 
         <LinearLayout style="@style/FxAccountSpacer" />
 
--- a/mobile/android/base/resources/layout/fxaccount_create_account_not_allowed.xml
+++ b/mobile/android/base/resources/layout/fxaccount_create_account_not_allowed.xml
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
    This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/.
 -->
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fillViewport="true" >
 
     <LinearLayout
         android:id="@+id/create_account_not_allowed_view"
         style="@style/FxAccountMiddle" >
 
         <LinearLayout style="@style/FxAccountSpacer" />
 
--- a/mobile/android/base/resources/layout/fxaccount_email_password_view.xml
+++ b/mobile/android/base/resources/layout/fxaccount_email_password_view.xml
@@ -3,41 +3,41 @@
    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/.
 -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <LinearLayout
-        android:layout_width="fill_parent"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical" >
 
         <AutoCompleteTextView
             android:id="@+id/email"
             style="@style/FxAccountEditItem"
             android:layout_marginBottom="10dp"
             android:completionThreshold="2"
             android:ems="10"
             android:hint="@string/fxaccount_email_hint"
             android:inputType="textEmailAddress" >
 
             <requestFocus />
         </AutoCompleteTextView>
 
         <LinearLayout
-            android:layout_width="fill_parent"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal" >
 
             <EditText
                 android:id="@+id/password"
                 style="@style/FxAccountEditItem"
-                android:layout_width="fill_parent"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
                 android:background="@drawable/fxaccount_password_background"
                 android:ems="10"
                 android:hint="@string/fxaccount_password_hint"
                 android:inputType="textPassword" />
 
             <!-- For the following, I beg forgiveness. The show/hide button is a
@@ -46,40 +46,40 @@
                  button's width regardless of its state. To achieve this, we
                  size the actual button to its container, and include two
                  invisible (but present for layout purposes) buttons, one of
                  each state. The container wraps the larger of the two dummy
                  buttons; the actual button sizes to the container; and we're
                  happy. Be thankful there are not three buttons! -->
             <FrameLayout
                 android:layout_width="wrap_content"
-                android:layout_height="fill_parent"
+                android:layout_height="match_parent"
                 android:layout_weight="0"
                 android:orientation="horizontal" >
 
                 <Button
                     android:id="@+id/show_password"
                     style="@style/FxAccountShowHidePasswordButton"
-                    android:layout_width="fill_parent"
-                    android:layout_height="fill_parent"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
                     android:text="@string/fxaccount_password_show" >
                 </Button>
 
                 <Button
                     style="@style/FxAccountShowHidePasswordButton"
                     android:layout_width="wrap_content"
-                    android:layout_height="fill_parent"
+                    android:layout_height="match_parent"
                     android:text="@string/fxaccount_password_show"
                     android:visibility="invisible" >
                 </Button>
 
                 <Button
                     style="@style/FxAccountShowHidePasswordButton"
                     android:layout_width="wrap_content"
-                    android:layout_height="fill_parent"
+                    android:layout_height="match_parent"
                     android:text="@string/fxaccount_password_hide"
                     android:visibility="invisible" >
                 </Button>
             </FrameLayout>
         </LinearLayout>
     </LinearLayout>
 
 </merge>
--- a/mobile/android/base/resources/layout/fxaccount_get_started.xml
+++ b/mobile/android/base/resources/layout/fxaccount_get_started.xml
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
    This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/.
 -->
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fillViewport="true" >
 
     <LinearLayout
         android:id="@+id/intro_view"
         style="@style/FxAccountMiddle" >
 
         <LinearLayout style="@style/FxAccountSpacer" />
 
--- a/mobile/android/base/resources/layout/fxaccount_preference_list_fragment.xml
+++ b/mobile/android/base/resources/layout/fxaccount_preference_list_fragment.xml
@@ -14,22 +14,22 @@
 ** 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.
 */
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
-    android:layout_height="fill_parent"
-    android:layout_width="fill_parent"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
     android:background="@android:color/transparent">
 
     <ListView android:id="@android:id/list"
-        android:layout_width="fill_parent"
+        android:layout_width="match_parent"
         android:layout_height="0px"
         android:layout_weight="1"
         android:paddingTop="0dip"
         android:paddingBottom="@dimen/preference_fragment_padding_bottom"
         android:paddingLeft="@dimen/preference_fragment_padding_side"
         android:paddingRight="@dimen/preference_fragment_padding_side"
         android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
         android:clipToPadding="false"
--- a/mobile/android/base/resources/layout/fxaccount_sign_in.xml
+++ b/mobile/android/base/resources/layout/fxaccount_sign_in.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
    This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/.
 -->
 
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fillViewport="true" >
 
     <LinearLayout
         android:id="@+id/sign_in_view"
         style="@style/FxAccountMiddle" >
 
         <LinearLayout style="@style/FxAccountSpacer" />
 
@@ -34,17 +34,17 @@
 
             <Button
                 android:id="@+id/button"
                 style="@style/FxAccountButton"
                 android:text="@string/fxaccount_sign_in_button_label" />
         </RelativeLayout>
 
         <LinearLayout
-            android:layout_width="fill_parent"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="10dp"
             android:orientation="horizontal" >
 
             <TextView
                 android:id="@+id/forgot_password_link"
                 style="@style/FxAccountLinkifiedItem"
                 android:layout_gravity="left"
--- a/mobile/android/base/resources/layout/fxaccount_status.xml
+++ b/mobile/android/base/resources/layout/fxaccount_status.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
    This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/.
 -->
 
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fillViewport="true" >
 
     <LinearLayout
         android:id="@+id/existing_user"
         style="@style/FxAccountMiddle" >
 
         <TextView
             style="@style/FxAccountHeaderItem"
@@ -28,51 +28,51 @@
             android:id="@+id/sync_status_text"
             style="@style/FxAccountHeaderItem"
             android:text="@string/fxaccount_status_sync" >
         </TextView>
 
         <ViewFlipper
             android:id="@+id/connection_status_view"
             style="@style/FxAccountTextItem"
-            android:layout_width="fill_parent"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content" >
 
             <TextView
                 android:id="@+id/needs_upgrade_view"
                 style="@style/FxAccountTextItem"
-                android:layout_width="fill_parent"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:background="#fad4d2"
                 android:drawablePadding="10dp"
                 android:drawableStart="@drawable/fxaccount_sync_error"
                 android:gravity="center_vertical"
                 android:padding="10dp"
                 android:text="@string/fxaccount_status_needs_upgrade" >
             </TextView>
 
             <TextView
                 android:id="@+id/sign_in_view"
                 style="@style/FxAccountTextItem"
-                android:layout_width="fill_parent"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:background="#fad4d2"
                 android:drawablePadding="10dp"
                 android:drawableStart="@drawable/fxaccount_sync_error"
                 android:gravity="center_vertical"
                 android:padding="10dp"
                 android:text="@string/fxaccount_status_needs_credentials" >
             </TextView>
 
             <TextView
                 android:id="@+id/unverified_view"
                 style="@style/FxAccountTextItem"
-                android:layout_width="fill_parent"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:background="#fad4d2"
                 android:drawablePadding="10dp"
                 android:drawableStart="@drawable/fxaccount_sync_error"
                 android:gravity="center_vertical"
                 android:padding="10dp"
                 android:text="@string/fxaccount_status_needs_verification" >
--- a/mobile/android/base/resources/layout/fxaccount_status_error_preference.xml
+++ b/mobile/android/base/resources/layout/fxaccount_status_error_preference.xml
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
+    android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="@color/fxaccount_error_preference_backgroundcolor"
     android:gravity="center_vertical"
     android:minHeight="?android:attr/listPreferredItemHeight"
     android:paddingRight="?android:attr/scrollbarSize" >
 
     <LinearLayout
         android:layout_width="wrap_content"
@@ -30,17 +30,17 @@
         android:layout_marginLeft="15dip"
         android:layout_marginRight="6dip"
         android:layout_marginTop="6dip"
         android:layout_weight="1" >
 
         <TextView
             android:id="@+android:id/title"
             style="@style/FxAccountTextItem"
-            android:layout_width="fill_parent"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:gravity="center_vertical" >
         </TextView>
     </RelativeLayout>
 
     <!-- We ignore summary and widget_frame, but they still need to be present.  We set them to be gone. -->
 
--- a/mobile/android/base/resources/layout/fxaccount_update_credentials.xml
+++ b/mobile/android/base/resources/layout/fxaccount_update_credentials.xml
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
    This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/.
 -->
 
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fillViewport="true" >
 
     <LinearLayout
         android:id="@+id/update_credentials_view"
         style="@style/FxAccountMiddle" >
 
         <LinearLayout style="@style/FxAccountSpacer" />
 
--- a/mobile/android/base/resources/layout/gecko_app.xml
+++ b/mobile/android/base/resources/layout/gecko_app.xml
@@ -1,107 +1,107 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 xmlns:gecko="http://schemas.android.com/apk/res-auto"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent">
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
 
     <ViewStub android:id="@+id/tabs_panel"
               android:layout="@layout/tabs_panel_view"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"/>
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"/>
 
    <view class="org.mozilla.gecko.GeckoApp$MainLayout"
          android:id="@+id/main_layout"
-         android:layout_width="fill_parent"
-         android:layout_height="fill_parent"
+         android:layout_width="match_parent"
+         android:layout_height="match_parent"
          android:background="@android:color/transparent">
 
         <RelativeLayout android:id="@+id/gecko_layout"
-                        android:layout_width="fill_parent"
-                        android:layout_height="fill_parent"
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
                         android:layout_above="@+id/find_in_page">
 
             <include layout="@layout/shared_ui_components"/>
 
             <FrameLayout android:id="@+id/home_pager_container"
-                         android:layout_width="fill_parent"
-                         android:layout_height="fill_parent"
+                         android:layout_width="match_parent"
+                         android:layout_height="match_parent"
                          android:visibility="gone">
 
                 <ViewStub android:id="@+id/home_pager_stub"
                           android:layout="@layout/home_pager"
-                          android:layout_width="fill_parent"
-                          android:layout_height="fill_parent"/>
+                          android:layout_width="match_parent"
+                          android:layout_height="match_parent"/>
 
                 <ViewStub android:id="@+id/home_banner_stub"
                           android:layout="@layout/home_banner"
-                          android:layout_width="fill_parent"
+                          android:layout_width="match_parent"
                           android:layout_height="@dimen/home_banner_height"
                           android:layout_gravity="bottom"/>
 
             </FrameLayout>
 
         </RelativeLayout>
 
         <org.mozilla.gecko.FindInPageBar android:id="@+id/find_in_page"
-                                         android:layout_width="fill_parent"
+                                         android:layout_width="match_parent"
                                          android:layout_height="wrap_content"
                                          android:layout_alignParentBottom="true"
                                          style="@style/FindBar"
                                          android:visibility="gone"/>
 
         <org.mozilla.gecko.MediaCastingBar android:id="@+id/media_casting"
-                                           android:layout_width="fill_parent"
+                                           android:layout_width="match_parent"
                                            android:layout_height="wrap_content"
                                            android:layout_alignParentBottom="true"
                                            style="@style/FindBar"
                                            android:visibility="gone"/>
 
         <FrameLayout android:id="@+id/search_container"
-                     android:layout_width="fill_parent"
-                     android:layout_height="fill_parent"
+                     android:layout_width="match_parent"
+                     android:layout_height="match_parent"
                      android:layout_below="@+id/browser_actionbar"
                      android:background="@android:color/white"
                      android:visibility="invisible"/>
 
         <!-- When focus is cleared from from BrowserToolbar's EditText to
              lower the virtual keyboard, focus will be returned to the root
              view. To make sure the EditText is not the first focusable view in
              the root view, BrowserToolbar should be specified as low in the
              view hierarchy as possible. -->
 
         <org.mozilla.gecko.widget.GeckoViewFlipper android:id="@id/browser_actionbar"
-                android:layout_width="fill_parent"
+                android:layout_width="match_parent"
                 android:layout_height="@dimen/browser_toolbar_height"
                 android:clickable="true"
                 android:focusable="true">
 
             <org.mozilla.gecko.toolbar.BrowserToolbar
                 android:id="@+id/browser_toolbar"
                 style="@style/BrowserToolbar"
-                android:layout_width="fill_parent"
+                android:layout_width="match_parent"
                 android:layout_height="@dimen/browser_toolbar_height"
                 android:clickable="true"
                 android:focusable="true"
                 android:background="@drawable/url_bar_bg"/>
 
             <org.mozilla.gecko.ActionModeCompatView android:id="@+id/actionbar"
-                                                    android:layout_height="fill_parent"
-                                                    android:layout_width="fill_parent"
+                                                    android:layout_height="match_parent"
+                                                    android:layout_width="match_parent"
                                                     style="@style/GeckoActionBar"/>
 
         </org.mozilla.gecko.widget.GeckoViewFlipper>
 
         <org.mozilla.gecko.toolbar.ToolbarProgressView android:id="@+id/progress"
-                                                       android:layout_width="fill_parent"
+                                                       android:layout_width="match_parent"
                                                        android:layout_height="14dp"
                                                        android:layout_marginTop="-8dp"
                                                        android:layout_below="@id/browser_actionbar"
                                                        android:src="@drawable/progress"
                                                        android:background="@null"
                                                        android:visibility="gone" />
 
     </view>
--- a/mobile/android/base/resources/layout/home_banner.xml
+++ b/mobile/android/base/resources/layout/home_banner.xml
@@ -1,15 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <org.mozilla.gecko.home.HomeBanner xmlns:android="http://schemas.android.com/apk/res/android"
                                    android:id="@+id/home_banner"
                                    style="@style/Widget.HomeBanner"
-                                   android:layout_width="fill_parent"
-                                   android:layout_height="fill_parent"
+                                   android:layout_width="match_parent"
+                                   android:layout_height="match_parent"
                                    android:background="@drawable/home_banner"
                                    android:gravity="center_vertical"
                                    android:visibility="gone"
                                    android:clickable="true"
                                    android:focusable="true"/>
--- a/mobile/android/base/resources/layout/home_banner_content.xml
+++ b/mobile/android/base/resources/layout/home_banner_content.xml
@@ -10,27 +10,27 @@
                 android:layout_width="48dip"
                 android:layout_height="48dip"
                 android:layout_marginLeft="10dp"
                 android:scaleType="centerInside"/>
 
      <org.mozilla.gecko.widget.EllipsisTextView
          android:id="@+id/text"
          android:layout_width="0dip"
-         android:layout_height="fill_parent"
+         android:layout_height="match_parent"
          android:layout_weight="1"
          android:layout_marginLeft="10dp"
          android:paddingTop="7dp"
          android:paddingBottom="7dp"
          android:textAppearance="@style/TextAppearance.Widget.HomeBanner"
          android:layout_gravity="bottom"
          android:gravity="center_vertical"
          gecko:ellipsizeAtLine="3"/>
 
     <ImageButton android:id="@+id/close"
                  android:layout_width="34dip"
-                 android:layout_height="fill_parent"
+                 android:layout_height="match_parent"
                  android:background="@drawable/home_banner"
                  android:scaleType="center"
                  android:contentDescription="@string/close_tab"
                  android:src="@drawable/tab_close"/>
 
 </merge>
--- a/mobile/android/base/resources/layout/home_bookmarks_panel.xml
+++ b/mobile/android/base/resources/layout/home_bookmarks_panel.xml
@@ -1,20 +1,20 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:layout_width="fill_parent"
-             android:layout_height="fill_parent">
+             android:layout_width="match_parent"
+             android:layout_height="match_parent">
 
     <ViewStub android:id="@+id/home_empty_view_stub"
               android:layout="@layout/home_empty_panel"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"/>
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"/>
 
     <org.mozilla.gecko.home.BookmarksListView
             android:id="@+id/bookmarks_list"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"/>
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
 
 </FrameLayout>
--- a/mobile/android/base/resources/layout/home_empty_panel.xml
+++ b/mobile/android/base/resources/layout/home_empty_panel.xml
@@ -1,33 +1,33 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:id="@+id/home_empty_view"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
               android:orientation="vertical"
               android:gravity="center"
               android:paddingLeft="50dp"
               android:paddingRight="50dp">
 
     <!-- Empty spacer view -->
-    <View android:layout_width="fill_parent"
+    <View android:layout_width="match_parent"
           android:layout_height="0dip"
           android:layout_weight="1"/>
 
     <ImageView android:id="@+id/home_empty_image"
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:gravity="top|center"
                android:scaleType="fitCenter"/>
 
     <TextView android:id="@+id/home_empty_text"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="0dip"
               android:gravity="top|center"
               android:textAppearance="@style/TextAppearance.EmptyMessage"
               android:layout_weight="3"/>
 
 </LinearLayout>
 
--- a/mobile/android/base/resources/layout/home_empty_reading_panel.xml
+++ b/mobile/android/base/resources/layout/home_empty_reading_panel.xml
@@ -1,48 +1,48 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:id="@+id/home_empty_view"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
               android:orientation="vertical"
               android:gravity="center">
 
     <!-- Empty spacer view -->
-    <View android:layout_width="fill_parent"
+    <View android:layout_width="match_parent"
           android:layout_height="0dip"
           android:layout_weight="1"/>
 
-    <ImageView android:layout_width="fill_parent"
+    <ImageView android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="top|center"
                android:scaleType="center"
                android:src="@drawable/icon_reading_list_empty"
                android:paddingBottom="10dp"/>
 
-    <TextView android:layout_width="fill_parent"
+    <TextView android:layout_width="match_parent"
               android:layout_height="0dip"
               android:gravity="top|center"
               android:text="@string/home_reading_list_empty"
               android:textAppearance="@style/TextAppearance.EmptyMessage"
               android:paddingLeft="50dp"
               android:paddingRight="50dp"
               android:layout_weight="3"/>
 
     <ImageView android:src="@drawable/divider_horizontal"
-               android:layout_width="fill_parent"
+               android:layout_width="match_parent"
                android:layout_height="1dip"
                android:paddingLeft="25dp"
                android:paddingRight="25dp"/>
 
     <TextView android:id="@+id/home_empty_hint"
-              android:layout_width="fill_parent"
+              android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:gravity="bottom"
               android:text="@string/home_reading_list_hint"
               android:textAppearance="@style/TextAppearance.Small"
               android:contentDescription="@string/home_reading_list_hint_accessible"
               android:paddingTop="20dp"
               android:paddingBottom="15dp"
               android:paddingLeft="25dp"
--- a/mobile/android/base/resources/layout/home_history_list.xml
+++ b/mobile/android/base/resources/layout/home_history_list.xml
@@ -2,23 +2,23 @@
 <!-- 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/. -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <ViewStub android:id="@+id/home_empty_view_stub"
               android:layout="@layout/home_empty_panel"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"/>
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"/>
 
     <TextView android:id="@+id/title"
               style="@style/Widget.Home.HistoryPanelTitle"
               android:visibility="gone"/>
 
     <org.mozilla.gecko.home.HomeListView
             android:id="@+id/list"
             style="@style/Widget.Home.HistoryListView"
-            android:layout_width="fill_parent"
+            android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1"/>
 
 </merge>
--- a/mobile/android/base/resources/layout/home_history_panel.xml
+++ b/mobile/android/base/resources/layout/home_history_panel.xml
@@ -1,24 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
               android:orientation="vertical">
 
     <FrameLayout android:id="@+id/history_panel_container"
-                 android:layout_width="fill_parent"
+                 android:layout_width="match_parent"
                  android:layout_height="0dp"
                  android:layout_weight="1" />
 
     <org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_icon_widget"
-                                            android:layout_width="fill_parent"
+                                            android:layout_width="match_parent"
                                             android:layout_height="@dimen/browser_toolbar_height"
                                             android:tabStripEnabled="false"
                                             android:showDividers="none"
                                             android:background="@color/background_light"
                                             android:layout="@layout/home_history_tabs_indicator"/>
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout/home_history_tabs_indicator.xml
+++ b/mobile/android/base/resources/layout/home_history_tabs_indicator.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="0dp"
-             android:layout_height="fill_parent"
+             android:layout_height="match_parent"
              android:layout_weight="1"
              android:background="@drawable/home_history_tabs_indicator"/>
--- a/mobile/android/base/resources/layout/home_item_row.xml
+++ b/mobile/android/base/resources/layout/home_item_row.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <org.mozilla.gecko.home.TwoLinePageRow xmlns:android="http://schemas.android.com/apk/res/android"
-                                       android:layout_width="fill_parent"
+                                       android:layout_width="match_parent"
                                        android:layout_height="@dimen/page_row_height"
                                        android:minHeight="@dimen/page_row_height"/>
--- a/mobile/android/base/resources/layout/home_last_tabs_panel.xml
+++ b/mobile/android/base/resources/layout/home_last_tabs_panel.xml
@@ -1,21 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
               android:orientation="vertical">
 
     <include layout="@layout/home_history_list"/>
 
-    <LinearLayout android:layout_width="fill_parent"
+    <LinearLayout android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:background="@color/home_button_bar_bg">
 
         <Button android:id="@+id/open_all_tabs_button"
                 style="@style/Widget.Home.ActionButton"
                 android:text="@string/home_last_tabs_open"
                 android:gravity="center"
                 android:visibility="gone"/>
--- a/mobile/android/base/resources/layout/home_most_recent_panel.xml
+++ b/mobile/android/base/resources/layout/home_most_recent_panel.xml
@@ -1,21 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="fill_parent"
-              android:layout_height="fill_parent"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
               android:orientation="vertical">
 
     <include layout="@layout/home_history_list"/>
 
-    <LinearLayout android:layout_width="fill_parent"
+    <LinearLayout android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:background="@color/home_button_bar_bg">
 
         <Button android:id="@+id/clear_history_button"
                 style="@style/Widget.Home.ActionButton"
                 android:text="@string/home_clear_history_button"
                 android:gravity="center"
                 android:visibility="gone"/>
--- a/mobile/android/base/resources/layout/home_pager.xml
+++ b/mobile/android/base/resources/layout/home_pager.xml
@@ -4,21 +4,21 @