diff --git a/browser/components/customizableui/CustomizableUI.jsm b/browser/components/customizableui/CustomizableUI.jsm
index 9ab4eb194409..c809f33f342c 100644
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -300,6 +300,13 @@ let CustomizableUIInternal = {
// We should still enter even if gSavedState.currentVersion >= kVersion
// because the per-widget pref facility is independent of versioning.
if (!gSavedState) {
+ // Flip all the prefs so we don't try to re-introduce later:
+ for (let [id, widget] of gPalette) {
+ if (widget.defaultArea && widget._introducedInVersion === "pref") {
+ let prefId = "browser.toolbarbuttons.introduced." + widget.id;
+ Services.prefs.setBoolPref(prefId, true);
+ }
+ }
return;
}
diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js
index e8ee05d3e156..95c7aaa30938 100644
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -175,28 +175,6 @@ const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
// days we will try to create a new one more aggressively.
const BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS = 3;
-// Record the current default search engine in Telemetry.
-function recordDefaultSearchEngine() {
- let engine;
- try {
- engine = Services.search.defaultEngine;
- } catch (e) {}
- let name;
-
- if (!engine) {
- name = "NONE";
- } else if (engine.identifier) {
- name = engine.identifier;
- } else if (engine.name) {
- name = "other-" + engine.name;
- } else {
- name = "UNDEFINED";
- }
-
- let engines = Services.telemetry.getKeyedHistogramById("SEARCH_DEFAULT_ENGINE");
- engines.add(name, true)
-}
-
// Factory object
const BrowserGlueServiceFactory = {
_instance: null,
@@ -476,14 +454,12 @@ BrowserGlue.prototype = {
ss.defaultEngine = ss.currentEngine;
else
ss.currentEngine = ss.defaultEngine;
- recordDefaultSearchEngine();
break;
case "browser-search-service":
if (data != "init-complete")
return;
Services.obs.removeObserver(this, "browser-search-service");
this._syncSearchEngines();
- recordDefaultSearchEngine();
break;
#ifdef NIGHTLY_BUILD
case "nsPref:changed":
diff --git a/browser/components/preferences/in-content/sync.js b/browser/components/preferences/in-content/sync.js
index 230aa9a73463..18abb82beec2 100644
--- a/browser/components/preferences/in-content/sync.js
+++ b/browser/components/preferences/in-content/sync.js
@@ -570,7 +570,7 @@ let gSyncPane = {
},
openChangeProfileImage: function() {
- fxAccounts.promiseAccountsChangeProfileURI("avatar")
+ fxAccounts.promiseAccountsChangeProfileURI("preferences", "avatar")
.then(url => {
this.openContentInBrowser(url, {
replaceQueryString: true
@@ -579,7 +579,7 @@ let gSyncPane = {
},
manageFirefoxAccount: function() {
- fxAccounts.promiseAccountsManageURI()
+ fxAccounts.promiseAccountsManageURI("preferences")
.then(url => {
this.openContentInBrowser(url, {
replaceQueryString: true
diff --git a/browser/components/privatebrowsing/test/browser/browser.ini b/browser/components/privatebrowsing/test/browser/browser.ini
index d0ee64575c9b..18bc27fafad3 100644
--- a/browser/components/privatebrowsing/test/browser/browser.ini
+++ b/browser/components/privatebrowsing/test/browser/browser.ini
@@ -17,9 +17,6 @@ support-files =
[browser_privatebrowsing_DownloadLastDirWithCPS.js]
[browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js]
-skip-if = true # Bug 1142678 - Loading a message sending frame script into a private about:home tab causes leaks
-[browser_privatebrowsing_aboutHomeButtonAfterWindowClose_old.js]
-skip-if = e10s
[browser_privatebrowsing_aboutSessionRestore.js]
[browser_privatebrowsing_cache.js]
[browser_privatebrowsing_certexceptionsui.js]
diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutHomeButtonAfterWindowClose_old.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutHomeButtonAfterWindowClose_old.js
deleted file mode 100644
index dc61c1e00191..000000000000
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutHomeButtonAfterWindowClose_old.js
+++ /dev/null
@@ -1,50 +0,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/. */
-
-// This test checks that the Session Restore about:home button
-// is disabled in private mode
-
-function test() {
- waitForExplicitFinish();
-
- function testNoSessionRestoreButton() {
- let win = OpenBrowserWindow({private: true});
- win.addEventListener("load", function onLoad() {
- win.removeEventListener("load", onLoad, false);
- executeSoon(function() {
- info("The second private window got loaded");
- let newTab = win.gBrowser.addTab();
- win.gBrowser.selectedTab = newTab;
- let tabBrowser = win.gBrowser.getBrowserForTab(newTab);
- tabBrowser.addEventListener("load", function tabLoadListener() {
- if (win.content.location != "about:home") {
- win.content.location = "about:home";
- return;
- }
- tabBrowser.removeEventListener("load", tabLoadListener, true);
- executeSoon(function() {
- info("about:home got loaded");
- let sessionRestoreButton = win.gBrowser
- .contentDocument
- .getElementById("restorePreviousSession");
- is(win.getComputedStyle(sessionRestoreButton).display,
- "none", "The Session Restore about:home button should be disabled");
- win.close();
- finish();
- });
- }, true);
- });
- }, false);
- }
-
- let win = OpenBrowserWindow({private: true});
- win.addEventListener("load", function onload() {
- win.removeEventListener("load", onload, false);
- executeSoon(function() {
- info("The first private window got loaded");
- win.close();
- testNoSessionRestoreButton();
- });
- }, false);
-}
diff --git a/browser/components/sessionstore/test/browser.ini b/browser/components/sessionstore/test/browser.ini
index 1eacb57ff6aa..bb289fa8d893 100644
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -96,8 +96,6 @@ skip-if = buildapp == 'mulet'
[browser_restore_redirect.js]
[browser_scrollPositions.js]
[browser_sessionHistory.js]
-# Disabled because of bug 1077581
-skip-if = e10s
[browser_sessionStorage.js]
[browser_swapDocShells.js]
skip-if = e10s # See bug 918634
diff --git a/browser/devtools/styleinspector/test/browser_ruleview_add-rule_01.js b/browser/devtools/styleinspector/test/browser_ruleview_add-rule_01.js
index 81fbbfb9df6b..21fe13a00275 100644
--- a/browser/devtools/styleinspector/test/browser_ruleview_add-rule_01.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_add-rule_01.js
@@ -22,7 +22,7 @@ let PAGE_CONTENT = [
const TEST_DATA = [
{ node: "#testid", expected: "#testid" },
{ node: ".testclass2", expected: ".testclass2" },
- { node: ".class1.class2", expected: ".class1" },
+ { node: ".class1.class2", expected: ".class1.class2" },
{ node: "p", expected: "p" }
];
@@ -95,4 +95,4 @@ function* testNewRule(view, expected, index) {
let lastRule = textProps[textProps.length - 1];
is(lastRule.name, "font-weight", "Last rule name is font-weight");
is(lastRule.value, "bold", "Last rule value is bold");
-}
\ No newline at end of file
+}
diff --git a/browser/locales/en-US/searchplugins/ddg.xml b/browser/locales/en-US/searchplugins/ddg.xml
index d68deb4b0df5..46f12792fec5 100644
--- a/browser/locales/en-US/searchplugins/ddg.xml
+++ b/browser/locales/en-US/searchplugins/ddg.xml
@@ -6,7 +6,7 @@
data:image/icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAATCwAAEwsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA11RgALs6oACbQ9wAj0v8AI9L/ACfQ9wAu0agANdUYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzzN4CNdL/oK/z//////////////////////+jsPv/BDXX/wAz0t4AAAAAAAAAAAAAAAAAAAAAAAAAAAAyzvNSduD//////8jK/v+P+Lf/IbQL/17RPP+J3Y//wOKX//////9YeuX/ADLO8wAAAAAAAAAAAAAAAAAw091piOX/8/X9/1Fx5P9xhu//WOWZ/0W9Lv9Lwjn/J8BB/xyDAP9bdfL/9fP//2mI5v8AMNPdAAAAAAc610YRQ9f//////0Zr4P8AGdD/sb32////////////wrv//wAh1/8MPab/ACPc/05r4///////EkPX/wc610YANtWkrr/y/6S48P8AJ9L/AB3R/+/w/v///////////3+D7f8AQeL/AYTw/wFr5/8AMNb/p7Tv/6698v8AM9WkADLW//////8yXt//AC3V/wAw1/////////////z///8A0P7/AKb1/wWI7P8AuPf/AJ3w/zZW3P//////ADHV/wAx2P//////AzrZ/wAu1/84ZOL////////////e////AND//wC1+f8Atff/AZbv/wY62f8ELNf//////wAw1/8AMtn//////wAw2f8ALNn/kKrz////+//cwbH////////////R////Rcb8/wDO/f8A/P//AHzo//////8AMNj/ADXa//////8vXuL/ACna/4yq9///79T/jUkg/9i+r///////r2Q0/7Cozv8BKdr/AirY/zdZ4P//////ADTa/wI72tOuv/T/prr0/wAl2v+JqPb//7yW/+bUxv/9+/n////u//W+n/+Op/L/ADPd/wAv2v+ru/T/r7/0/wI72tMLQd1DEEjg//////9Cbef/ADng///////////////////////R3///AC3g/wAy3v9SeOn//////xFI4P8LQd1DAAAAAAM64PNmiuz/9/j//2mN7f/m7P3///////////9Cb+n/ACXd/wAt3v9rju3//////2iL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/P8J0vz/ELDz/xt85v8mSdj/JknY/yZJ2P8lStowJUjXYCZJ2P8nSdhwJErZryZK2f8oSNcgJUnajyZK2f8mStn/JkrZ/yZK2f8mStn/iJPA////////////////////////////0ff+/xjV/P8J0vz/Drn1/xiO6/8Yjuv/GI7r/xCw8/8Lyvr/CdL8/xmF6P8mStn/JkrZ/yVJ2o8oSNcgJkrZ/yRK2a8jStrfI0rZ3wAAAAAlSdq/Jkra/yZK2v8mStr/Jkra/yZK2v+xtsf///////////////////////////8o2Pz/CdL8/wvK+v8mStr/Jkra/yZK2v8mStr/Jkra/yZK2v8iW97/Jkra/yZK2v8mStr/JUnavwAAAAAjStnfI0ra3yZK2v8lSdq/AAAAACZH2O8mStr/Jkra/yZK2v8mStr/L1HY/9HR0f///////////////////////////yjY/P8J0vz/CdL8/xCw9P8QsPT/ELD0/xSf7/8ddeX/Jkra/yZK2v8mStr/Jkra/yZK2v8mR9jvAAAAACVJ2r8mStr/Jkvb/yVJ2r8AAAAAJkvb/yZL2/8mS9v/Jkvb/yZL2/9KZtL/4+Pj////////////////////////////4Pn//0fd/f8J0vz/CdL8/wnS/P8J0vz/CdL8/wnS/P8Lyvr/Fpfu/yJc3/8mS9v/Jkvb/yZL2/8AAAAAJUnavyZL2/8mS9z/JUncvwAAAAAmS9z/Jkvc/yZL3P8mS9z/Jkvc/26AyP/x8fH//////////////////////////////////////9H3/v/C9P7/o+7+/2fa+/8Oufb/CdL8/wnS/P8J0vz/CdL8/xiP7P8mS9z/Jkvc/wAAAAAlSdy/Jkvc/yZM3P8lTNy/AAAAACZJ2e8mTNz/Jkzc/yZM3P8mTNz/iJTB////////////qnth/5VaOf/x6eX///////////////////////Hp5f/x6eX/ydL2/yZM3P8kVN7/G37o/xKo8v8QsfT/HXbm/yZM3P8mSdnvAAAAACVM3L8mTNz/I0vc3yZJ2u8AAAAAJUzevyZM3f8mTN3/Jkzd/yZM3f+fqc3///////////+VWjn/v5yI/+re1///////////////////////jk8s/7iRe//J0vb/Jkzd/yZM3f8mTN3/Jkzd/yZM3f8mTN3/Jkzd/yVM3r8AAAAAI0vc3yNL3N8kTd2vJk3d/yhQ3yAlTd2PJk3d/yZN3f8mTd3/Jk3d/6St0v////////////Hp5f/q3tf///////////////////////////+xhm7/49PK/6Cx8P8mTd3/Jk3d/yZN3f8mTd3/Jk3d/yZN3f8mTd3/JU3djyhQ3yAmTd3/JE3drydN33AmTd7/J03fcCVK3zAmTd7/Jk3e/yZN3v8mTd7/pK7S///////Sp5r/////////////////////////////////////////////////T27k/yZN3v8mTd7/Jk3e/yZN3v8mTd7/Jk3e/yZN3v8lSt8wJ03fcCZN3v8nTd9wKFDfICZO3/8mTt3PAAAAACVN3r8mTt//Jk7f/yZO3/+EltX//////+fRyv/SqaD/59LO///////////////////////at63/vIBy/7Glxf8mTt//Jk7f/yZO3/8mTt//Jk7f/yZO3/8mTt//JU3evwAAAAAmTt3PJk7f/yhQ3yAAAAAAJE/dryZO3/8oUN9AKFDfQCZO3/8mTt//Jk7f/zhb2v/o6/T/////////////////////////////////////////////////XHrn/yZO3/8mTt//Jk7f/yZO3/8mTt//Jk7f/yZO3/8oUN9AKFDfQCZO3/8kT92vAAAAAAAAAAAoUN9AJk7g/yZO4M8AAAAAJk/hnyZO4P8mTuD/Jk7g/05v5v/k6fv//////////////////////////////////////3eR7P8mTuD/Jk7g/yZO4P8mTuD/Jk7g/yZO4P8mTuD/Jk/hnwAAAAAmTuDPJk7g/yhQ30AAAAAAAAAAAAAAAAAjT+GfJU/h/yVO4Y8gUN8QIk7gzyVP4f8lT+H/SWnW/0lp1v+bq+H/8fHx/////////////////6Cy8v9OcOb/JU/h/yVP4f8lT+H/JU/h/yVP4f8lT+H/JU/h/yJO4M8gUN8QJU7hjyVP4f8jT+GfAAAAAAAAAAAAAAAAAAAAACBQ3xAlTOHvJU/h/yVQ4mAgUN8QIk7hzyVP4f+ktOv///////////////////////H0/f9phur/JU/h/yVP4f8lT+H/JU/h/yVP4f8lT+H/JU/h/yVP4f8iTuHPIFDfECVQ4mAlT+H/JUzh7yBQ3xAAAAAAAAAAAAAAAAAAAAAAAAAAACVQ3zAlUOLvJVDi/yVQ4mAgUN8QI1Din4mb2//J0/j/ydP4/6299P93ku3/M1vk/yVQ4v8lUOL/JVDi/yVQ4v8lUOL/JVDi/yVQ4v8lUOL/I1DinyBQ3xAlUOJgJVDi/yVQ4u8lUN8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACVQ5DAlUOLvJVDi/yVQ4o8AAAAAJFDjQCVQ4r8lUOL/JVDi/yVQ4v8lUOL/JVDi/yVQ4v8lUOL/JVDi/yVQ4v8lUOL/JVDivyRQ40AAAAAAJVDijyVQ4v8lUOLvJVDkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACVQ5DAjUeTfJVHj/yNR5N8kUONAAAAAACVQ5DAmUuOAJVHivyNR5N8lUeP/JVHj/yNR5N8lUeK/JlLjgCVQ5DAAAAAAJFDjQCNR5N8lUeP/I1Hk3yVQ5DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBQ3xAjUuSfJVHk/yVR5P8jUeTfJFLkcChQ5yAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoUOcgJFLkcCNR5N8lUeT/JVHk/yNS5J8gUN8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkUONAI1LknyVS5P8lUuT/JVLk/yVS5O8lUeS/JVHkvyVR5L8lUeS/JVLk7yVS5P8lUuT/JVLk/yRS468kUONAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIFDfECVS5GAjUuWfIlPlzyVS5f8lUuX/JVLl/yVS5f8iU+XPI1LlnyVS5GAgUN8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AA///AAD//AAAP/ggBB/wgAEP4AAAB8AAAAPAAAADiAAAEYAAAAEQAAAIAAAAAAAAAAAgAAAEIAAABCAAAAQgAAAEIAAABCAAAAQAAAAAAAAAABAAAAiAAAABiAAAEcAAAAPAAAAD4AAAB/CAAQ/4IAQf/AfgP/8AAP//wAP/
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAYAAADovjFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoxNTg5QTM3RjNCMjA2ODExODIyQUVEOUNBRDIxQzhDMyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxRTYyNzYzMzFBQUUxMUU0ODc3NTg3NjMyNDFCNzExQSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxRTYyNzYzMjFBQUUxMUU0ODc3NTg3NjMyNDFCNzExQSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDE4MDExNzQwNzIwNjgxMTg3MUZCQUIxMEI4RjU1NzYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MTU4OUEzN0YzQjIwNjgxMTgyMkFFRDlDQUQyMUM4QzMiLz4gPC9yZGY6RGVzY3Jp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
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAYAAABGkOCVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoxNTg5QTM3RjNCMjA2ODExODIyQUVEOUNBRDIxQzhDMyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4RTdBNDY4ODFBQUQxMUU0ODc3NTg3NjMyNDFCNzExQSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4RTdBNDY4NzFBQUQxMUU0ODc3NTg3NjMyNDFCNzExQSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6OTE3MzgzQ0I2QjIwNjgxMTgyMkFFRDlDQUQyMUM4QzMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MTU4OUEzN0YzQjIwNjgxMTgyMkFFRDlDQUQyMUM4QzMiLz4gPC9yZGY6RGVzY3Jp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
-
+
diff --git a/layout/base/PositionedEventTargeting.cpp b/layout/base/PositionedEventTargeting.cpp
index 078986e728f2..409f0f907378 100644
--- a/layout/base/PositionedEventTargeting.cpp
+++ b/layout/base/PositionedEventTargeting.cpp
@@ -76,7 +76,7 @@ struct EventRadiusPrefs
bool mRegistered;
bool mTouchOnly;
bool mRepositionEventCoords;
- bool mTouchClusterDetection;
+ bool mTouchClusterDetectionDisabled;
uint32_t mLimitReadableSize;
};
@@ -125,8 +125,8 @@ GetPrefsFor(EventClassID aEventClassID)
nsPrintfCString repositionPref("ui.%s.radius.reposition", prefBranch);
Preferences::AddBoolVarCache(&prefs->mRepositionEventCoords, repositionPref.get(), false);
- nsPrintfCString touchClusterPref("ui.zoomedview.enabled", prefBranch);
- Preferences::AddBoolVarCache(&prefs->mTouchClusterDetection, touchClusterPref.get(), false);
+ nsPrintfCString touchClusterPref("ui.zoomedview.disabled", prefBranch);
+ Preferences::AddBoolVarCache(&prefs->mTouchClusterDetectionDisabled, touchClusterPref.get(), true);
nsPrintfCString limitReadableSizePref("ui.zoomedview.limitReadableSize", prefBranch);
Preferences::AddUintVarCache(&prefs->mLimitReadableSize, limitReadableSizePref.get(), 8);
@@ -396,7 +396,7 @@ GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame,
static bool
IsElementClickableAndReadable(nsIFrame* aFrame, WidgetGUIEvent* aEvent, const EventRadiusPrefs* aPrefs)
{
- if (!aPrefs->mTouchClusterDetection) {
+ if (aPrefs->mTouchClusterDetectionDisabled) {
return true;
}
@@ -487,7 +487,7 @@ FindFrameTargetedByInputEvent(WidgetGUIEvent* aEvent,
GetClosest(aRootFrame, aPointRelativeToRootFrame, targetRect, prefs,
restrictToDescendants, candidates, &elementsInCluster);
if (closestClickable) {
- if ((prefs->mTouchClusterDetection && elementsInCluster > 1) ||
+ if ((!prefs->mTouchClusterDetectionDisabled && elementsInCluster > 1) ||
(!IsElementClickableAndReadable(closestClickable, aEvent, prefs))) {
if (aEvent->mClass == eMouseEventClass) {
WidgetMouseEventBase* mouseEventBase = aEvent->AsMouseEventBase();
diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js
index 5d14c9f80892..f7cc4a62af02 100644
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -403,7 +403,7 @@ pref("font.size.inflation.minTwips", 0);
// When true, zooming will be enabled on all sites, even ones that declare user-scalable=no.
pref("browser.ui.zoom.force-user-scalable", false);
-pref("ui.zoomedview.enabled", false);
+pref("ui.zoomedview.disabled", false);
pref("ui.zoomedview.limitReadableSize", 8); // value in layer pixels
pref("ui.touch.radius.enabled", false);
diff --git a/mobile/android/tests/browser/robocop/testOfflinePage.js b/mobile/android/tests/browser/robocop/testOfflinePage.js
index b29d03cba6e1..71b206085ddb 100644
--- a/mobile/android/tests/browser/robocop/testOfflinePage.js
+++ b/mobile/android/tests/browser/robocop/testOfflinePage.js
@@ -18,6 +18,37 @@ function is(lhs, rhs, text) {
do_report_result(lhs === rhs, text, Components.stack.caller, false);
}
+function promiseBrowserEvent(browser, eventType) {
+ return new Promise((resolve) => {
+ function handle(event) {
+ // Since we'll be redirecting, don't make assumptions about the given URL and the loaded URL
+ if (event.target != browser.contentDocument || event.target.location.href == "about:blank") {
+ do_print("Skipping spurious '" + eventType + "' event" + " for " + event.target.location.href);
+ return;
+ }
+ do_print("Received event " + eventType + " from browser");
+ browser.removeEventListener(eventType, handle, true);
+ resolve(event);
+ }
+
+ browser.addEventListener(eventType, handle, true);
+ do_print("Now waiting for " + eventType + " event from browser");
+ });
+}
+
+// Provide a helper to yield until we are sure the offline state has changed
+function promiseOffline(isOffline) {
+ return new Promise((resolve, reject) => {
+ function observe(subject, topic, data) {
+ do_print("Received topic: " + topic);
+ Services.obs.removeObserver(observe, "network:offline-status-changed");
+ resolve();
+ }
+ Services.obs.addObserver(observe, "network:offline-status-changed", false);
+ Services.io.offline = isOffline;
+ });
+}
+
// The chrome window
let chromeWin;
@@ -29,7 +60,7 @@ let proxyPrefValue;
const kUniqueURI = Services.io.newURI("http://mochi.test:8888/tests/robocop/video_controls.html", null, null);
-add_test(function setup_browser() {
+add_task(function* test_offline() {
// Tests always connect to localhost, and per bug 87717, localhost is now
// reachable in offline mode. To avoid this, disable any proxy.
proxyPrefValue = Services.prefs.getIntPref("network.proxy.type");
@@ -47,29 +78,15 @@ add_test(function setup_browser() {
Services.io.offline = false;
});
- do_test_pending();
-
// Add a new tab with a blank page so we can better control the real page load and the offline state
browser = BrowserApp.addTab("about:blank", { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
// Go offline, expecting the error page.
- Services.io.offline = true;
+ yield promiseOffline(true);
// Load our test web page
- browser.addEventListener("DOMContentLoaded", errorListener, true);
browser.loadURI(kUniqueURI.spec, null, null)
-});
-
-//------------------------------------------------------------------------------
-// listen to loading the neterror page. (offline mode)
-function errorListener() {
- if (browser.contentWindow.location == "about:blank") {
- do_print("got about:blank, which is expected once, so return");
- return;
- }
-
- browser.removeEventListener("DOMContentLoaded", errorListener, true);
- ok(Services.io.offline, "Services.io.offline is true.");
+ yield promiseBrowserEvent(browser, "DOMContentLoaded");
// This is an error page.
is(browser.contentDocument.documentURI.substring(0, 27), "about:neterror?e=netOffline", "Document URI is the error page.");
@@ -79,29 +96,17 @@ function errorListener() {
Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
- // Now press the "Try Again" button, with offline mode off.
- Services.io.offline = false;
-
- browser.addEventListener("DOMContentLoaded", reloadListener, true);
+ // Go online and try to load the page again
+ yield promiseOffline(false);
ok(browser.contentDocument.getElementById("errorTryAgain"), "The error page has got a #errorTryAgain element");
+
+ // Click "Try Again" button to start the page load
browser.contentDocument.getElementById("errorTryAgain").click();
-}
-
-
-//------------------------------------------------------------------------------
-// listen to reload of neterror.
-function reloadListener() {
- browser.removeEventListener("DOMContentLoaded", reloadListener, true);
-
- ok(!Services.io.offline, "Services.io.offline is false.");
+ yield promiseBrowserEvent(browser, "DOMContentLoaded");
// This is not an error page.
is(browser.contentDocument.documentURI, kUniqueURI.spec, "Document URI is not the offline-error page, but the original URI.");
-
- do_test_finished();
-
- run_next_test();
-}
+});
run_next_test();
diff --git a/services/fxaccounts/FxAccounts.jsm b/services/fxaccounts/FxAccounts.jsm
index d5de2fb17750..a7997c4187d0 100644
--- a/services/fxaccounts/FxAccounts.jsm
+++ b/services/fxaccounts/FxAccounts.jsm
@@ -1200,7 +1200,7 @@ FxAccountsInternal.prototype = {
// the current account's profile image.
// if settingToEdit is set, the profile page should hightlight that setting
// for the user to edit.
- promiseAccountsChangeProfileURI: function(settingToEdit = null) {
+ promiseAccountsChangeProfileURI: function(entrypoint, settingToEdit = null) {
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.settings.uri");
if (settingToEdit) {
@@ -1220,13 +1220,16 @@ FxAccountsInternal.prototype = {
let newQueryPortion = url.indexOf("?") == -1 ? "?" : "&";
newQueryPortion += "email=" + encodeURIComponent(accountData.email);
newQueryPortion += "&uid=" + encodeURIComponent(accountData.uid);
+ if (entrypoint) {
+ newQueryPortion += "&entrypoint=" + encodeURIComponent(entrypoint);
+ }
return url + newQueryPortion;
}).then(result => currentState.resolve(result));
},
// Returns a promise that resolves with the URL to use to manage the current
// user's FxA acct.
- promiseAccountsManageURI: function() {
+ promiseAccountsManageURI: function(entrypoint) {
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.settings.uri");
if (this._requireHttps() && !/^https:/.test(url)) { // Comment to un-break emacs js-mode highlighting
throw new Error("Firefox Accounts server must use HTTPS");
@@ -1242,6 +1245,9 @@ FxAccountsInternal.prototype = {
let newQueryPortion = url.indexOf("?") == -1 ? "?" : "&";
newQueryPortion += "uid=" + encodeURIComponent(accountData.uid) +
"&email=" + encodeURIComponent(accountData.email);
+ if (entrypoint) {
+ newQueryPortion += "&entrypoint=" + encodeURIComponent(entrypoint);
+ }
return url + newQueryPortion;
}).then(result => currentState.resolve(result));
},
diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js
index c5163cde2dff..4e62d713cd8f 100644
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -2861,10 +2861,14 @@ Engine.prototype = {
},
get searchForm() {
+ return this._getSearchFormWithPurpose();
+ },
+
+ _getSearchFormWithPurpose(aPurpose = "") {
// First look for a
var searchFormURL = this._getURLOfType(URLTYPE_SEARCH_HTML, "searchform");
if (searchFormURL) {
- let submission = searchFormURL.getSubmission("", this);
+ let submission = searchFormURL.getSubmission("", this, aPurpose);
// If the rel=searchform URL is not type="get" (i.e. has postData),
// ignore it, since we can only return a URL.
@@ -2947,7 +2951,7 @@ Engine.prototype = {
if (!aData) {
// Return a dummy submission object with our searchForm attribute
- return new Submission(makeURI(this.searchForm), null);
+ return new Submission(makeURI(this._getSearchFormWithPurpose(aPurpose)), null);
}
LOG("getSubmission: In data: \"" + aData + "\"; Purpose: \"" + aPurpose + "\"");
diff --git a/toolkit/components/search/tests/xpcshell/data/engine-rel-searchform-purpose.xml b/toolkit/components/search/tests/xpcshell/data/engine-rel-searchform-purpose.xml
new file mode 100644
index 000000000000..18026210fcc8
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/data/engine-rel-searchform-purpose.xml
@@ -0,0 +1,11 @@
+
+
+engine-rel-searchform-purpose
+
+
+
+
+
+
+
+
diff --git a/toolkit/components/search/tests/xpcshell/test_purpose.js b/toolkit/components/search/tests/xpcshell/test_purpose.js
index 107e9fbb8127..56c26de8a06f 100644
--- a/toolkit/components/search/tests/xpcshell/test_purpose.js
+++ b/toolkit/components/search/tests/xpcshell/test_purpose.js
@@ -46,5 +46,13 @@ add_task(function* test_purpose() {
check_submission("&channel=fflb", "foo", "application/x-moz-default-purpose", "keyword");
check_submission("", "foo", "application/x-moz-default-purpose", "invalid");
+ // Tests for a purpose on the search form (ie. empty query).
+ [engine] = yield addTestEngines([
+ { name: "engine-rel-searchform-purpose", xmlFileName: "engine-rel-searchform-purpose.xml" }
+ ]);
+ base = "http://www.google.com/search?q=";
+ check_submission("&channel=sb", "", null, "searchbar");
+ check_submission("&channel=sb", "", "text/html", "searchbar");
+
do_test_finished();
});
diff --git a/toolkit/components/search/tests/xpcshell/xpcshell.ini b/toolkit/components/search/tests/xpcshell/xpcshell.ini
index e08e931fb6b3..2cc53dcc002a 100644
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -13,6 +13,7 @@ support-files =
data/engineMaker.sjs
data/engine-rel-searchform.xml
data/engine-rel-searchform-post.xml
+ data/engine-rel-searchform-purpose.xml
data/engineImages.xml
data/ico-size-16x16-png.ico
data/invalid-engine.xml
diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json
index 14941b93f9c4..f698c28d3852 100644
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -4722,13 +4722,6 @@
"releaseChannelCollection": "opt-out",
"description": "Record the search counts for search engines"
},
- "SEARCH_DEFAULT_ENGINE": {
- "expires_in_version": "never",
- "kind": "flag",
- "keyed": true,
- "releaseChannelCollection": "opt-out",
- "description": "Record the default search engine."
- },
"SEARCH_SERVICE_INIT_MS": {
"expires_in_version": "never",
"kind": "exponential",
diff --git a/toolkit/components/telemetry/TelemetryController.jsm b/toolkit/components/telemetry/TelemetryController.jsm
index 795e740e160e..183e190c9e40 100644
--- a/toolkit/components/telemetry/TelemetryController.jsm
+++ b/toolkit/components/telemetry/TelemetryController.jsm
@@ -24,6 +24,8 @@ Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
Cu.import("resource://gre/modules/TelemetryUtils.jsm", this);
+const Utils = TelemetryUtils;
+
const LOGGER_NAME = "Toolkit.Telemetry";
const LOGGER_PREFIX = "TelemetryController::";
@@ -52,12 +54,11 @@ const TELEMETRY_TEST_DELAY = 100;
// Timeout after which we consider a ping submission failed.
const PING_SUBMIT_TIMEOUT_MS = 2 * 60 * 1000;
-// We treat pings before midnight as happening "at midnight" with this tolerance.
-const MIDNIGHT_TOLERANCE_MS = 15 * 60 * 1000;
// For midnight fuzzing we want to affect pings around midnight with this tolerance.
const MIDNIGHT_TOLERANCE_FUZZ_MS = 5 * 60 * 1000;
// We try to spread "midnight" pings out over this interval.
const MIDNIGHT_FUZZING_INTERVAL_MS = 60 * 60 * 1000;
+// We delay sending "midnight" pings on this client by this interval.
const MIDNIGHT_FUZZING_DELAY_MS = Math.random() * MIDNIGHT_FUZZING_INTERVAL_MS;
// Ping types.
@@ -532,7 +533,16 @@ let Impl = {
* @return Number The next time (ms from UNIX epoch) when we can send pings.
*/
_getNextPingSendTime: function(now) {
- const midnight = TelemetryUtils.getNearestMidnight(now, MIDNIGHT_FUZZING_INTERVAL_MS);
+ // 1. First we check if the time is between 11pm and 1am. If it's not, we send
+ // immediately.
+ // 2. If we confirmed the time is indeed between 11pm and 1am in step 1, we
+ // then check if the time is also 11:55pm or later. If it's not, we send
+ // immediately.
+ // 3. Finally, if the time is between 11:55pm and 1am, we disallow sending
+ // before (midnight + fuzzing delay), which is a random time between 12am-1am
+ // (decided at startup).
+
+ const midnight = Utils.getNearestMidnight(now, MIDNIGHT_FUZZING_INTERVAL_MS);
// Don't delay ping if we are not close to midnight.
if (!midnight) {
diff --git a/toolkit/components/telemetry/TelemetryEnvironment.jsm b/toolkit/components/telemetry/TelemetryEnvironment.jsm
index a1e047ed313a..546cd8704065 100644
--- a/toolkit/components/telemetry/TelemetryEnvironment.jsm
+++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm
@@ -154,6 +154,8 @@ const PREF_UPDATE_AUTODOWNLOAD = "app.update.auto";
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
const EXPERIMENTS_CHANGED_TOPIC = "experiments-changed";
+const SEARCH_ENGINE_MODIFIED_TOPIC = "browser-search-engine-modified";
+const SEARCH_SERVICE_TOPIC = "browser-search-service";
/**
* Turn a millisecond timestamp into a day timestamp.
@@ -651,6 +653,8 @@ function EnvironmentCache() {
};
this._updateSettings();
+ // Fill in the default search engine, if the search provider is already initialized.
+ this._updateSearchEngine();
// Build the remaining asynchronous parts of the environment. Don't register change listeners
// until the initial environment has been built.
@@ -663,21 +667,21 @@ function EnvironmentCache() {
p.push(this._updateProfile());
#endif
+ let setup = () => {
+ this._initTask = null;
+ this._startWatchingPrefs();
+ this._addonBuilder.watchForChanges();
+ this._addObservers();
+ return this.currentEnvironment;
+ };
+
this._initTask = Promise.all(p)
.then(
- () => {
- this._initTask = null;
- this._startWatchingPrefs();
- this._addonBuilder.watchForChanges();
- return this.currentEnvironment;
- },
+ () => setup(),
(err) => {
// log errors but eat them for consumers
this._log.error("EnvironmentCache - error while initializing", err);
- this._initTask = null;
- this._startWatchingPrefs();
- this._addonBuilder.watchForChanges();
- return this.currentEnvironment;
+ return setup();
});
}
EnvironmentCache.prototype = {
@@ -799,6 +803,90 @@ EnvironmentCache.prototype = {
}
},
+ _addObservers: function () {
+ // Watch the search engine change and service topics.
+ Services.obs.addObserver(this, SEARCH_ENGINE_MODIFIED_TOPIC, false);
+ Services.obs.addObserver(this, SEARCH_SERVICE_TOPIC, false);
+ },
+
+ _removeObservers: function () {
+ // Remove the search engine change and service observers.
+ Services.obs.removeObserver(this, SEARCH_ENGINE_MODIFIED_TOPIC);
+ Services.obs.removeObserver(this, SEARCH_SERVICE_TOPIC);
+ },
+
+ observe: function (aSubject, aTopic, aData) {
+ this._log.trace("observe - aTopic: " + aTopic + ", aData: " + aData);
+ switch (aTopic) {
+ case SEARCH_ENGINE_MODIFIED_TOPIC:
+ if (aData != "engine-default" && aData != "engine-current") {
+ return;
+ }
+ // Record the new default search choice and send the change notification.
+ this._onSearchEngineChange();
+ break;
+ case SEARCH_SERVICE_TOPIC:
+ if (aData != "init-complete") {
+ return;
+ }
+ // Now that the search engine init is complete, record the default search choice.
+ this._updateSearchEngine();
+ break;
+ }
+ },
+
+ /**
+ * Get the default search engine.
+ * @return {String} Returns the search engine identifier, "NONE" if no default search
+ * engine is defined or "UNDEFINED" if no engine identifier or name can be found.
+ */
+ _getDefaultSearchEngine: function () {
+ let engine;
+ try {
+ engine = Services.search.defaultEngine;
+ } catch (e) {}
+
+ let name;
+ if (!engine) {
+ name = "NONE";
+ } else if (engine.identifier) {
+ name = engine.identifier;
+ } else if (engine.name) {
+ name = "other-" + engine.name;
+ } else {
+ name = "UNDEFINED";
+ }
+
+ return name;
+ },
+
+ /**
+ * Update the default search engine value.
+ */
+ _updateSearchEngine: function () {
+ this._log.trace("_updateSearchEngine - isInitialized: " + Services.search.isInitialized);
+ if (!Services.search.isInitialized) {
+ return;
+ }
+
+ // Make sure we have a settings section.
+ this._currentEnvironment.settings = this._currentEnvironment.settings || {};
+ // Update the search engine entry in the current environment.
+ this._currentEnvironment.settings.defaultSearchEngine = this._getDefaultSearchEngine();
+ },
+
+ /**
+ * Update the default search engine value and trigger the environment change.
+ */
+ _onSearchEngineChange: function () {
+ this._log.trace("_onSearchEngineChange");
+
+ // Finally trigger the environment change notification.
+ let oldEnvironment = Cu.cloneInto(this._currentEnvironment, myScope);
+ this._updateSearchEngine();
+ this._onEnvironmentChange("search-engine-changed", oldEnvironment);
+ },
+
/**
* Get the build data in object form.
* @return Object containing the build data.
diff --git a/toolkit/components/telemetry/TelemetrySession.jsm b/toolkit/components/telemetry/TelemetrySession.jsm
index 549fa478d6c1..82f20e2702b1 100644
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -22,6 +22,8 @@ Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
Cu.import("resource://gre/modules/TelemetryUtils.jsm", this);
+const Utils = TelemetryUtils;
+
const myScope = this;
const IS_CONTENT_PROCESS = (function() {
@@ -424,7 +426,7 @@ let TelemetryScheduler = {
timeout = SCHEDULER_TICK_IDLE_INTERVAL_MS;
// We need to make sure though that we don't miss sending pings around
// midnight when we use the longer idle intervals.
- const nextMidnight = TelemetryUtils.getNextMidnight(now);
+ const nextMidnight = Utils.getNextMidnight(now);
timeout = Math.min(timeout, nextMidnight.getTime() - now.getTime());
}
@@ -435,8 +437,8 @@ let TelemetryScheduler = {
_sentDailyPingToday: function(nowDate) {
// This is today's date and also the previous midnight (0:00).
- const todayDate = TelemetryUtils.truncateToDays(nowDate);
- const nearestMidnight = TelemetryUtils.getNearestMidnight(nowDate, SCHEDULER_MIDNIGHT_TOLERANCE_MS);
+ const todayDate = Utils.truncateToDays(nowDate);
+ const nearestMidnight = Utils.getNearestMidnight(nowDate, SCHEDULER_MIDNIGHT_TOLERANCE_MS);
// If we are close to midnight, we check against that, otherwise against the last midnight.
const checkDate = nearestMidnight || todayDate;
// We consider a ping sent for today if it occured after midnight, or prior within the tolerance.
@@ -457,7 +459,7 @@ let TelemetryScheduler = {
return false;
}
- const nearestMidnight = TelemetryUtils.getNearestMidnight(nowDate, SCHEDULER_MIDNIGHT_TOLERANCE_MS);
+ const nearestMidnight = Utils.getNearestMidnight(nowDate, SCHEDULER_MIDNIGHT_TOLERANCE_MS);
if (!sentPingToday && !nearestMidnight) {
// Computer must have gone to sleep, the daily ping is overdue.
this._log.trace("_isDailyPingDue - daily ping is overdue... computer went to sleep?");
@@ -567,7 +569,7 @@ let TelemetryScheduler = {
let nextSessionCheckpoint =
this._lastSessionCheckpointTime + ABORTED_SESSION_UPDATE_INTERVAL_MS;
let combineActions = (shouldSendDaily && isAbortedPingDue) || (shouldSendDaily &&
- TelemetryUtils.areTimesClose(now, nextSessionCheckpoint,
+ Utils.areTimesClose(now, nextSessionCheckpoint,
SCHEDULER_COALESCE_THRESHOLD_MS));
if (combineActions) {
@@ -613,7 +615,7 @@ let TelemetryScheduler = {
// update the schedules.
this._saveAbortedPing(now.getTime(), competingPayload);
// If we're close to midnight, skip today's daily ping and reschedule it for tomorrow.
- let nearestMidnight = TelemetryUtils.getNearestMidnight(now, SCHEDULER_MIDNIGHT_TOLERANCE_MS);
+ let nearestMidnight = Utils.getNearestMidnight(now, SCHEDULER_MIDNIGHT_TOLERANCE_MS);
if (nearestMidnight) {
this._lastDailyPingTime = now.getTime();
}
@@ -1102,8 +1104,8 @@ let Impl = {
getMetadata: function getMetadata(reason) {
this._log.trace("getMetadata - Reason " + reason);
- let sessionStartDate = toLocalTimeISOString(TelemetryUtils.truncateToDays(this._sessionStartDate));
- let subsessionStartDate = toLocalTimeISOString(TelemetryUtils.truncateToDays(this._subsessionStartDate));
+ let sessionStartDate = toLocalTimeISOString(Utils.truncateToDays(this._sessionStartDate));
+ let subsessionStartDate = toLocalTimeISOString(Utils.truncateToDays(this._subsessionStartDate));
// Compute the subsession length in milliseconds, then convert to seconds.
let subsessionLength =
Math.floor((Policy.now() - this._subsessionStartDate.getTime()) / 1000);
diff --git a/toolkit/components/telemetry/TelemetryStorage.jsm b/toolkit/components/telemetry/TelemetryStorage.jsm
index 6474128bc6e1..8f3f07dbac20 100644
--- a/toolkit/components/telemetry/TelemetryStorage.jsm
+++ b/toolkit/components/telemetry/TelemetryStorage.jsm
@@ -1029,8 +1029,8 @@ let TelemetryStorageImpl = {
removeAbortedSessionPing: function() {
return this._abortedSessionSerializer.enqueueTask(Task.async(function*() {
try {
+ yield OS.File.remove(gAbortedSessionFilePath, { ignoreAbsent: false });
this._log.trace("removeAbortedSessionPing - success");
- yield OS.File.remove(gAbortedSessionFilePath);
} catch (ex if ex.becauseNoSuchFile) {
this._log.trace("removeAbortedSessionPing - no such file");
} catch (ex) {
diff --git a/toolkit/components/telemetry/docs/environment.rst b/toolkit/components/telemetry/docs/environment.rst
index 201553403fca..2471fc673508 100644
--- a/toolkit/components/telemetry/docs/environment.rst
+++ b/toolkit/components/telemetry/docs/environment.rst
@@ -34,6 +34,7 @@ Structure::
settings: {
blocklistEnabled: , // true on failure
isDefaultBrowser: , // null on failure, not available on Android
+ defaultSearchEngine: , // e.g. "yahoo"
e10sEnabled: , // false on failure
telemetryEnabled: , // false on failure
locale: , // e.g. "it", null on failure
@@ -189,3 +190,16 @@ Structure::
persona: , // id of the current persona, null on GONK
},
}
+
+Settings
+--------
+
+defaultSearchEngine
+~~~~~~~~~~~~~~~~~~~
+Contains the string identifier or name of the default search engine provider. This will not be present in environment data collected before the Search Service initialization.
+
+The special value ``NONE`` could occur if there is no default search engine.
+
+The special value ``UNDEFINED`` could occur if a default search engine exists but its identifier could not be determined.
+
+This field's contents are ``Services.search.defaultEngine.identifier`` (if defined) or ``"other-"`` + ``Services.search.defaultEngine.name`` if not. In other words, search engines without an ``.identifier`` are prefixed with ``other-``.
diff --git a/toolkit/components/telemetry/tests/search/chrome.manifest b/toolkit/components/telemetry/tests/search/chrome.manifest
new file mode 100644
index 000000000000..ec412e05081f
--- /dev/null
+++ b/toolkit/components/telemetry/tests/search/chrome.manifest
@@ -0,0 +1,3 @@
+locale testsearchplugin ar jar:jar:searchTest.jar!/chrome/searchTest.jar!/
+content testsearchplugin ./
+
diff --git a/toolkit/components/telemetry/tests/search/searchTest.jar b/toolkit/components/telemetry/tests/search/searchTest.jar
new file mode 100644
index 000000000000..b10fc0c3eca3
Binary files /dev/null and b/toolkit/components/telemetry/tests/search/searchTest.jar differ
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
index 2ce0c1846b70..7ac570ba98b5 100644
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -280,6 +280,11 @@ function checkSettingsSection(data) {
Assert.ok(checkNullOrString(update.channel));
Assert.equal(typeof update.enabled, "boolean");
Assert.equal(typeof update.autoDownload, "boolean");
+
+ // Check "defaultSearchEngine" separately, as it can either be undefined or string.
+ if ("defaultSearchEngine" in data.settings) {
+ checkString(data.settings.defaultSearchEngine);
+ }
}
function checkProfileSection(data) {
@@ -561,6 +566,8 @@ function checkEnvironmentData(data) {
}
function run_test() {
+ // Load a custom manifest to provide search engine loading from JAR files.
+ do_load_manifest("chrome.manifest");
do_test_pending();
spoofGfxAdapter();
do_get_profile();
@@ -936,6 +943,64 @@ add_task(function* test_changeThrottling() {
TelemetryEnvironment.unregisterChangeListener("testWatchPrefs_throttling");
});
+add_task(function* test_defaultSearchEngine() {
+ // Check that no default engine is in the environment before the search service is
+ // initialized.
+ let data = TelemetryEnvironment.currentEnvironment;
+ checkEnvironmentData(data);
+ Assert.ok(!("defaultSearchEngine" in data.settings));
+
+ // Load the engines definitions from a custom JAR file: that's needed so that
+ // the search provider reports an engine identifier.
+ let defaultBranch = Services.prefs.getDefaultBranch(null);
+ defaultBranch.setCharPref("browser.search.jarURIs", "chrome://testsearchplugin/locale/searchplugins/");
+ defaultBranch.setBoolPref("browser.search.loadFromJars", true);
+
+ // Initialize the search service and disable geoip lookup, so we don't get unwanted
+ // network connections.
+ Preferences.set("browser.search.geoip.url", "");
+ yield new Promise(resolve => Services.search.init(resolve));
+
+ // Our default engine from the JAR file has an identifier. Check if it is correctly
+ // reported.
+ data = TelemetryEnvironment.currentEnvironment;
+ checkEnvironmentData(data);
+ Assert.equal(data.settings.defaultSearchEngine, "telemetrySearchIdentifier");
+
+ // Remove all the search engines.
+ for (let engine of Services.search.getEngines()) {
+ Services.search.removeEngine(engine);
+ }
+ // The search service does not notify "engine-default" when removing a default engine.
+ // Manually force the notification.
+ // TODO: remove this when bug 1165341 is resolved.
+ Services.obs.notifyObservers(null, "browser-search-engine-modified", "engine-default");
+
+ // Then check that no default engine is reported if none is available.
+ data = TelemetryEnvironment.currentEnvironment;
+ checkEnvironmentData(data);
+ Assert.equal(data.settings.defaultSearchEngine, "NONE");
+
+ // Add a new search engine (this will have no engine identifier).
+ const SEARCH_ENGINE_ID = "telemetry_default";
+ const SEARCH_ENGINE_URL = "http://www.example.org/?search={searchTerms}";
+ Services.search.addEngineWithDetails(SEARCH_ENGINE_ID, "", null, "", "get", SEARCH_ENGINE_URL);
+
+ // Set the clock in the future so our changes don't get throttled.
+ gNow = fakeNow(futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE));
+ // Register a new change listener and then wait for the search engine change to be notified.
+ let deferred = PromiseUtils.defer();
+ TelemetryEnvironment.registerChangeListener("testWatch_SearchDefault", deferred.resolve);
+ Services.search.defaultEngine = Services.search.getEngineByName(SEARCH_ENGINE_ID);
+ yield deferred.promise;
+
+ data = TelemetryEnvironment.currentEnvironment;
+ checkEnvironmentData(data);
+
+ const EXPECTED_SEARCH_ENGINE = "other-" + SEARCH_ENGINE_ID;
+ Assert.equal(data.settings.defaultSearchEngine, EXPECTED_SEARCH_ENGINE);
+});
+
add_task(function*() {
do_test_finished();
});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
index 152e8fd67433..c31d082a7de9 100644
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -1363,6 +1363,39 @@ add_task(function* test_abortedSession() {
yield TelemetrySession.shutdown();
});
+add_task(function* test_abortedSession_Shutdown() {
+ if (gIsAndroid || gIsGonk) {
+ // We don't have the aborted session ping here.
+ return;
+ }
+
+ const ABORTED_FILE = OS.Path.join(DATAREPORTING_PATH, ABORTED_PING_FILE_NAME);
+
+ let schedulerTickCallback = null;
+ let now = fakeNow(2040, 1, 1, 0, 0, 0);
+ // Fake scheduler functions to control aborted-session flow in tests.
+ fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
+ yield TelemetrySession.reset();
+
+ Assert.ok((yield OS.File.exists(DATAREPORTING_PATH)),
+ "Telemetry must create the aborted session directory when starting.");
+
+ // Fake now again so that the scheduled aborted-session save takes place.
+ now = fakeNow(futureDate(now, ABORTED_SESSION_UPDATE_INTERVAL_MS));
+ // The first aborted session checkpoint must take place right after the initialisation.
+ Assert.ok(!!schedulerTickCallback);
+ // Execute one scheduler tick.
+ yield schedulerTickCallback();
+ // Check that the aborted session is due at the correct time.
+ Assert.ok((yield OS.File.exists(ABORTED_FILE)), "There must be an aborted session ping.");
+
+ // Remove the aborted session file and then shut down to make sure exceptions (e.g file
+ // not found) do not compromise the shutdown.
+ yield OS.File.remove(ABORTED_FILE);
+
+ yield TelemetrySession.shutdown();
+});
+
add_task(function* test_abortedDailyCoalescing() {
if (gIsAndroid || gIsGonk) {
// We don't have the aborted session or the daily ping here.
diff --git a/toolkit/components/telemetry/tests/unit/xpcshell.ini b/toolkit/components/telemetry/tests/unit/xpcshell.ini
index d1d8f498c3fc..a104590209d8 100644
--- a/toolkit/components/telemetry/tests/unit/xpcshell.ini
+++ b/toolkit/components/telemetry/tests/unit/xpcshell.ini
@@ -5,6 +5,8 @@ skip-if = toolkit == 'gonk'
# The *.xpi files are only needed for test_TelemetryEnvironment.js, but
# xpcshell fails to install tests if we move them under the test entry.
support-files =
+ ../search/chrome.manifest
+ ../search/searchTest.jar
dictionary.xpi
experiment.xpi
extension.xpi
diff --git a/toolkit/devtools/server/actors/styles.js b/toolkit/devtools/server/actors/styles.js
index 39a6da7aa2fa..6f24981867c8 100644
--- a/toolkit/devtools/server/actors/styles.js
+++ b/toolkit/devtools/server/actors/styles.js
@@ -851,7 +851,7 @@ var PageStyleActor = protocol.ActorClass({
if (rawNode.id) {
selector = "#" + rawNode.id;
} else if (rawNode.className) {
- selector = "." + rawNode.className.split(" ")[0];
+ selector = "." + rawNode.className.split(" ").join(".");
} else {
selector = rawNode.tagName.toLowerCase();
}