Merge fx-team to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-05-21 16:32:12 -04:00
Родитель 6471344dd5 a21f838d9f
Коммит 5c44a0f852
28 изменённых файлов: 332 добавлений и 159 удалений

Просмотреть файл

@ -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" }
];
@ -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");
}
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -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
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.

Просмотреть файл

@ -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 ./

Двоичные данные
toolkit/components/telemetry/tests/search/searchTest.jar Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -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();
}