зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to b2g-inbound. a=merge
This commit is contained in:
Коммит
5c44a0f852
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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" }
|
||||
];
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
|
|
@ -2861,10 +2861,14 @@ Engine.prototype = {
|
|||
},
|
||||
|
||||
get searchForm() {
|
||||
return this._getSearchFormWithPurpose();
|
||||
},
|
||||
|
||||
_getSearchFormWithPurpose(aPurpose = "") {
|
||||
// First look for a <Url rel="searchform">
|
||||
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 + "\"");
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>engine-rel-searchform-purpose</ShortName>
|
||||
<Url type="text/html" method="GET" template="http://www.google.com/search" resultdomain="google.com" rel="searchform">
|
||||
<Param name="q" value="{searchTerms}"/>
|
||||
<!-- Dynamic parameters -->
|
||||
<MozParam name="channel" condition="purpose" purpose="contextmenu" value="rcs"/>
|
||||
<MozParam name="channel" condition="purpose" purpose="keyword" value="fflb"/>
|
||||
<MozParam name="channel" condition="purpose" purpose="searchbar" value="sb"/>
|
||||
</Url>
|
||||
</SearchPlugin>
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
this._initTask = Promise.all(p)
|
||||
.then(
|
||||
() => {
|
||||
let setup = () => {
|
||||
this._initTask = null;
|
||||
this._startWatchingPrefs();
|
||||
this._addonBuilder.watchForChanges();
|
||||
this._addObservers();
|
||||
return this.currentEnvironment;
|
||||
},
|
||||
};
|
||||
|
||||
this._initTask = Promise.all(p)
|
||||
.then(
|
||||
() => 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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -34,6 +34,7 @@ Structure::
|
|||
settings: {
|
||||
blocklistEnabled: <bool>, // true on failure
|
||||
isDefaultBrowser: <bool>, // null on failure, not available on Android
|
||||
defaultSearchEngine: <string>, // e.g. "yahoo"
|
||||
e10sEnabled: <bool>, // false on failure
|
||||
telemetryEnabled: <bool>, // false on failure
|
||||
locale: <string>, // e.g. "it", null on failure
|
||||
|
@ -189,3 +190,16 @@ Structure::
|
|||
persona: <string>, // 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-``.
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
locale testsearchplugin ar jar:jar:searchTest.jar!/chrome/searchTest.jar!/
|
||||
content testsearchplugin ./
|
||||
|
Двоичный файл не отображается.
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче