Merge m-c to inbound, a=merge

This commit is contained in:
Wes Kocher 2015-06-15 18:34:29 -07:00
commit b554609a11
55 changed files with 849 additions and 298 deletions

View File

@ -51,9 +51,15 @@ function debug(msg) {
/**
* An empirically determined amount of acceleration corresponding to a
* shake
* shake.
*/
const EXCITEMENT_THRESHOLD = 500;
/**
* The maximum fraction to update the excitement value per frame. This
* corresponds to requiring shaking for approximately 10 motion events (1.6
* seconds)
*/
const EXCITEMENT_FILTER_ALPHA = 0.2;
const DEVICE_MOTION_EVENT = "devicemotion";
const SCREEN_CHANGE_EVENT = "screenchange";
const CAPTURE_LOGS_CONTENT_EVENT = "requestSystemLogs";
@ -88,6 +94,11 @@ let LogShake = {
*/
captureRequested: false,
/**
* The current excitement (movement) level
*/
excitement: 0,
/**
* Map of files which have log-type information to their parsers
*/
@ -122,6 +133,9 @@ let LogShake = {
screenEnabled: true
}});
// Reset excitement to clear residual motion
this.excitement = 0;
SystemAppProxy.addEventListener(CAPTURE_LOGS_CONTENT_EVENT, this, false);
SystemAppProxy.addEventListener(SCREEN_CHANGE_EVENT, this, false);
@ -196,9 +210,12 @@ let LogShake = {
var acc = event.accelerationIncludingGravity;
var excitement = acc.x * acc.x + acc.y * acc.y + acc.z * acc.z;
// Updates excitement by a factor of at most alpha, ignoring sudden device
// motion. See bug #1101994 for more information.
var newExcitement = acc.x * acc.x + acc.y * acc.y + acc.z * acc.z;
this.excitement += (newExcitement - this.excitement) * EXCITEMENT_FILTER_ALPHA;
if (excitement > EXCITEMENT_THRESHOLD) {
if (this.excitement > EXCITEMENT_THRESHOLD) {
this.startCapture();
}
},

View File

@ -15,9 +15,14 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/LogCapture.jsm");
Cu.import("resource://gre/modules/LogShake.jsm");
// Force logshake to handle a device motion event with given components
// Does not use SystemAppProxy because event needs special
// accelerationIncludingGravity property
const EVENTS_PER_SECOND = 6.25;
const GRAVITY = 9.8;
/**
* Force logshake to handle a device motion event with given components.
* Does not use SystemAppProxy because event needs special
* accelerationIncludingGravity property.
*/
function sendDeviceMotionEvent(x, y, z) {
let event = {
type: "devicemotion",
@ -30,8 +35,10 @@ function sendDeviceMotionEvent(x, y, z) {
LogShake.handleEvent(event);
}
// Send a screen change event directly, does not use SystemAppProxy due to race
// conditions.
/**
* Send a screen change event directly, does not use SystemAppProxy due to race
* conditions.
*/
function sendScreenChangeEvent(screenEnabled) {
let event = {
type: "screenchange",
@ -42,23 +49,41 @@ function sendScreenChangeEvent(screenEnabled) {
LogShake.handleEvent(event);
}
function debug(msg) {
var timestamp = Date.now();
dump("LogShake: " + timestamp + ": " + msg);
/**
* Mock the readLogFile function of LogCapture.
* Used to detect whether LogShake activates.
* @return {Array<String>} Locations that LogShake tries to read
*/
function mockReadLogFile() {
let readLocations = [];
LogCapture.readLogFile = function(loc) {
readLocations.push(loc);
return null; // we don't want to provide invalid data to a parser
};
// Allow inspection of readLocations by caller
return readLocations;
}
/**
* Send a series of events that corresponds to a shake
*/
function sendSustainedShake() {
// Fire a series of devicemotion events that are of shake magnitude
for (let i = 0; i < 2 * EVENTS_PER_SECOND; i++) {
sendDeviceMotionEvent(0, 2 * GRAVITY, 2 * GRAVITY);
}
}
add_test(function test_do_log_capture_after_shaking() {
// Enable LogShake
LogShake.init();
let readLocations = [];
LogCapture.readLogFile = function(loc) {
readLocations.push(loc);
return null; // we don't want to provide invalid data to a parser
};
let readLocations = mockReadLogFile();
// Fire a devicemotion event that is of shake magnitude
sendDeviceMotionEvent(9001, 9001, 9001);
sendSustainedShake();
ok(readLocations.length > 0,
"LogShake should attempt to read at least one log");
@ -71,36 +96,28 @@ add_test(function test_do_nothing_when_resting() {
// Enable LogShake
LogShake.init();
let readLocations = [];
LogCapture.readLogFile = function(loc) {
readLocations.push(loc);
return null; // we don't want to provide invalid data to a parser
};
let readLocations = mockReadLogFile();
// Fire a devicemotion event that is relatively tiny
sendDeviceMotionEvent(0, 9.8, 9.8);
// Fire several devicemotion events that are relatively tiny
for (let i = 0; i < 2 * EVENTS_PER_SECOND; i++) {
sendDeviceMotionEvent(0, GRAVITY, GRAVITY);
}
ok(readLocations.length === 0,
"LogShake should not read any logs");
debug("test_do_nothing_when_resting: stop");
LogShake.uninit();
run_next_test();
});
add_test(function test_do_nothing_when_disabled() {
debug("test_do_nothing_when_disabled: start");
// Disable LogShake
LogShake.uninit();
let readLocations = [];
LogCapture.readLogFile = function(loc) {
readLocations.push(loc);
return null; // we don't want to provide invalid data to a parser
};
let readLocations = mockReadLogFile();
// Fire a devicemotion event that would normally be a shake
sendDeviceMotionEvent(0, 9001, 9001);
// Fire a series of events that would normally be a shake
sendSustainedShake();
ok(readLocations.length === 0,
"LogShake should not read any logs");
@ -112,18 +129,13 @@ add_test(function test_do_nothing_when_screen_off() {
// Enable LogShake
LogShake.init();
// Send an event as if the screen has been turned off
sendScreenChangeEvent(false);
let readLocations = [];
LogCapture.readLogFile = function(loc) {
readLocations.push(loc);
return null; // we don't want to provide invalid data to a parser
};
let readLocations = mockReadLogFile();
// Fire a devicemotion event that would normally be a shake
sendDeviceMotionEvent(0, 9001, 9001);
// Fire a series of events that would normally be a shake
sendSustainedShake();
ok(readLocations.length === 0,
"LogShake should not read any logs");
@ -145,8 +157,8 @@ add_test(function test_do_log_capture_resilient_readLogFile() {
throw new Error("Exception during readLogFile for: " + loc);
};
// Fire a devicemotion event that is of shake magnitude
sendDeviceMotionEvent(9001, 9001, 9001);
// Fire a series of events that would normally be a shake
sendSustainedShake();
ok(readLocations.length > 0,
"LogShake should attempt to read at least one log");
@ -168,8 +180,8 @@ add_test(function test_do_log_capture_resilient_parseLog() {
return null;
};
// Fire a devicemotion event that is of shake magnitude
sendDeviceMotionEvent(9001, 9001, 9001);
// Fire a series of events that would normally be a shake
sendSustainedShake();
ok(readLocations.length > 0,
"LogShake should attempt to read at least one log");
@ -178,7 +190,29 @@ add_test(function test_do_log_capture_resilient_parseLog() {
run_next_test();
});
add_test(function test_do_nothing_when_dropped() {
// Enable LogShake
LogShake.init();
let readLocations = mockReadLogFile();
// We want a series of spikes to be ignored by LogShake. This roughly
// corresponds to the compare_stairs_sock graph on bug #1101994
for (let i = 0; i < 10 * EVENTS_PER_SECOND; i++) {
// Fire a devicemotion event that is at rest
sendDeviceMotionEvent(0, 0, GRAVITY);
// Fire a spike of motion
sendDeviceMotionEvent(0, 2 * GRAVITY, 2 * GRAVITY);
}
ok(readLocations.length === 0,
"LogShake should not read any logs");
LogShake.uninit();
run_next_test();
});
function run_test() {
debug("Starting");
run_next_test();
}

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -151,7 +151,7 @@
<project name="platform/vendor/qcom/copper" path="device/qcom/msm8974" revision="ec7bc1a26610922156d7d412b4d3de6b4adb93da"/>
<project name="vendor_broadcom_wlan" path="vendor/broadcom/wlan" remote="b2g" revision="114b9491a8a919687da4e22fbd89fab511d6d8d7"/>
<!-- Shinano specific things -->
<project name="device-shinano" path="device/sony/shinano" remote="b2g" revision="a7cb315bc0704f589858feb2a34956364acacb08"/>
<project name="device-shinano" path="device/sony/shinano" remote="b2g" revision="afb93dac826346fdeaab6f8ce5dd70eaaaec676d"/>
<!-- Aries specific things -->
<project name="device-aries" path="device/sony/aries" remote="b2g" revision="75c7e6ca80d0c7a53f346ecfcde2343be95808c9"/>
<project name="device-aries" path="device/sony/aries" remote="b2g" revision="2916e2368074b5383c80bf5a0fba3fc83ba310bd"/>
</manifest>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="94516f787d477dc307e4566f415e0d2f0794f6b9"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "0c073eda92b099bc008488e52edb0745c5f7975e",
"git_revision": "62ba52866f4e5ca9120dad5bfe62fc5df981dc39",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "43b90c58070717da08d510200a0c848da68a4390",
"revision": "e54f587baa2008376f2439fb6901fdb99a878a99",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="94516f787d477dc307e4566f415e0d2f0794f6b9"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="0c073eda92b099bc008488e52edb0745c5f7975e"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="62ba52866f4e5ca9120dad5bfe62fc5df981dc39"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -206,8 +206,36 @@ AppendDistroSearchDirs(nsIProperties* aDirSvc, nsCOMArray<nsIFile> &array)
NS_IMETHODIMP
DirectoryProvider::GetFiles(const char *aKey, nsISimpleEnumerator* *aResult)
{
/**
* We want to preserve the following order, since the search service loads
* engines in first-loaded-wins order.
* - distro search plugin locations (Loaded by the search service using
* NS_APP_DISTRIBUTION_SEARCH_DIR_LIST)
*
* - engines shipped in chrome (Loaded from jar files by the search
* service)
*
* Then other locations, from NS_APP_SEARCH_DIR_LIST:
* - extension search plugin locations (prepended below using
* NS_NewUnionEnumerator)
* - user search plugin locations (profile)
* - app search plugin location (shipped engines)
*/
nsresult rv;
if (!strcmp(aKey, NS_APP_DISTRIBUTION_SEARCH_DIR_LIST)) {
nsCOMPtr<nsIProperties> dirSvc
(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
if (!dirSvc)
return NS_ERROR_FAILURE;
nsCOMArray<nsIFile> distroFiles;
AppendDistroSearchDirs(dirSvc, distroFiles);
return NS_NewArrayEnumerator(aResult, distroFiles);
}
if (!strcmp(aKey, NS_APP_SEARCH_DIR_LIST)) {
nsCOMPtr<nsIProperties> dirSvc
(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
@ -216,16 +244,6 @@ DirectoryProvider::GetFiles(const char *aKey, nsISimpleEnumerator* *aResult)
nsCOMArray<nsIFile> baseFiles;
/**
* We want to preserve the following order, since the search service loads
* engines in first-loaded-wins order.
* - extension search plugin locations (prepended below using
* NS_NewUnionEnumerator)
* - distro search plugin locations
* - user search plugin locations (profile)
* - app search plugin location (shipped engines)
*/
AppendDistroSearchDirs(dirSvc, baseFiles);
AppendFileKey(NS_APP_USER_SEARCH_DIR, dirSvc, baseFiles);
AppendFileKey(NS_APP_SEARCH_DIR, dirSvc, baseFiles);

View File

@ -70,6 +70,7 @@ support-files =
[browser_cmd_pagemod_export.js]
support-files =
browser_cmd_pagemod_export.html
[browser_cmd_paintflashing.js]
[browser_cmd_pref1.js]
[browser_cmd_pref2.js]
[browser_cmd_pref3.js]

View File

@ -0,0 +1,58 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the paintflashing command correctly sets its state.
"use strict";
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
"test/browser_cmd_cookie.html";
function test() {
return Task.spawn(testTask).then(finish, helpers.handleError);
}
let tests = {
testInput: function(options) {
let toggleCommand = options.requisition.system.commands.get("paintflashing toggle");
let actions = [
{
command: "paintflashing on",
isChecked: true,
label: "checked after on"
},
{
command: "paintflashing off",
isChecked: false,
label: "unchecked after off"
},
{
command: "paintflashing toggle",
isChecked: true,
label: "checked after toggle"
},
{
command: "paintflashing toggle",
isChecked: false,
label: "unchecked after toggle"
}
];
return helpers.audit(options, actions.map(spec => ({
setup: spec.command,
exec: {},
post: () => is(toggleCommand.state.isChecked(), spec.isChecked, spec.label)
})));
},
};
function* testTask() {
let options = yield helpers.openTab(TEST_URI);
yield helpers.openToolbar(options);
yield helpers.runTests(options, tests);
yield helpers.closeToolbar(options);
yield helpers.closeTab(options);
}

View File

@ -7,23 +7,28 @@
* Utility functions for collapsing markers into a waterfall.
*/
loader.lazyRequireGetter(this, "getBlueprintFor",
"devtools/performance/marker-utils", true);
loader.lazyRequireGetter(this, "MarkerUtils",
"devtools/performance/marker-utils");
/**
* Collapses markers into a tree-like structure.
* @param object markerNode
* @param array markersList
* @param array filter
*/
function collapseMarkersIntoNode({ markerNode, markersList }) {
function collapseMarkersIntoNode({ markerNode, markersList, filter }) {
let { getCurrentParentNode, collapseMarker, addParentNode, popParentNode } = createParentNodeFactory(markerNode);
for (let i = 0, len = markersList.length; i < len; i++) {
let curr = markersList[i];
let parentNode = getCurrentParentNode();
let blueprint = getBlueprintFor(curr);
// If this marker type should not be displayed, just skip
if (!MarkerUtils.isMarkerValid(curr, filter)) {
continue;
}
let parentNode = getCurrentParentNode();
let blueprint = MarkerUtils.getBlueprintFor(curr);
let collapse = blueprint.collapseFunc || (() => null);
let peek = distance => markersList[i + distance];

View File

@ -136,7 +136,8 @@ support-files =
[browser_profiler_tree-view-08.js]
[browser_profiler_tree-view-09.js]
[browser_profiler_tree-view-10.js]
[browser_timeline-filters.js]
[browser_timeline-filters-01.js]
[browser_timeline-filters-02.js]
[browser_timeline-waterfall-background.js]
[browser_timeline-waterfall-generic.js]
[browser_timeline-waterfall-rerender.js]

View File

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests markers filtering mechanism.
*/
const URL = EXAMPLE_URL + "doc_innerHTML.html";
function* spawnTest() {
let { panel } = yield initPerformance(URL);
let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
yield startRecording(panel);
ok(true, "Recording has started.");
yield waitUntil(() => {
let markers = PerformanceController.getCurrentRecording().getMarkers();
return markers.some(m => m.name == "Parse HTML") &&
markers.some(m => m.name == "Javascript");
});
let waterfallRendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
yield stopRecording(panel);
$("#filter-button").click();
let filterJS = $("menuitem[marker-type=Javascript]");
yield waterfallRendered;
ok($(".waterfall-marker-bar[type=Javascript]"), "Found at least one 'Javascript' marker");
ok(!$(".waterfall-marker-bar[type='Parse HTML']"), "Found no Parse HTML markers as they are nested still");
EventUtils.synthesizeMouseAtCenter(filterJS, {type: "mouseup"}, panel.panelWin);
yield Promise.all([
WaterfallView.once(EVENTS.WATERFALL_RENDERED),
once(filterJS, "command")
]);
ok(!$(".waterfall-marker-bar[type=Javascript]"), "Javascript markers are all hidden.");
ok($(".waterfall-marker-bar[type='Parse HTML']"),
"Found at least one 'Parse HTML' marker still visible after hiding JS markers");
yield teardown(panel);
finish();
}

View File

@ -113,6 +113,10 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
*/
_onObservedPrefChange: function(_, prefName) {
this._hiddenMarkers = PerformanceController.getPref("hidden-markers");
// Clear the cache as we'll need to recompute the collapsed
// marker model
this._cache = new WeakMap();
},
/**
@ -137,6 +141,7 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
WaterfallUtils.collapseMarkersIntoNode({
markerNode: rootMarkerNode,
markersList: markers,
filter: this._hiddenMarkers
});
this._cache.set(markers, rootMarkerNode);

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_URI = "data:text/html;charset=utf-8," +
"<p>browser_telemetry_button_paintflashing.js</p>";
@ -30,27 +32,28 @@ function* testButton(toolbox, Telemetry) {
let button = toolbox.doc.querySelector("#command-button-paintflashing");
ok(button, "Captain, we have the button");
yield delayedClicks(button, 4);
yield* delayedClicks(toolbox, button, 4);
checkResults("_PAINTFLASHING_", Telemetry);
}
function delayedClicks(node, clicks) {
return new Promise(resolve => {
let clicked = 0;
function* delayedClicks(toolbox, node, clicks) {
for (let i = 0; i < clicks; i++) {
yield new Promise(resolve => {
// See TOOL_DELAY for why we need setTimeout here
setTimeout(() => resolve(), TOOL_DELAY);
});
// See TOOL_DELAY for why we need setTimeout here
setTimeout(function delayedClick() {
info("Clicking button " + node.id);
node.click();
clicked++;
// this event will fire once the command execution starts and
// the output object is created
let clicked = toolbox._requisition.commandOutputManager.onOutput.once();
if (clicked >= clicks) {
resolve(node);
} else {
setTimeout(delayedClick, TOOL_DELAY);
}
}, TOOL_DELAY);
});
info("Clicking button " + node.id);
node.click();
let outputEvent = yield clicked;
// promise gets resolved once execution finishes and output is ready
yield outputEvent.output.promise;
}
}
function checkResults(histIdFocus, Telemetry) {

View File

@ -516,10 +516,6 @@ size. -->
the text of a button; we expect more than one device. -->
<!ENTITY home_remote_tabs_unhide_selected_devices "Unhide selected devices">
<!ENTITY private_browsing_title "Private Browsing">
<!ENTITY private_tabs_panel_empty_desc "Your private tabs will show up here. While we don\'t keep any of your browsing history or cookies, bookmarks and files that you download will still be saved on your device.">
<!ENTITY private_tabs_panel_learn_more "Want to learn more?">
<!ENTITY remote_tabs_panel_moved_title "Where did my tabs go?">
<!ENTITY remote_tabs_panel_moved_desc "We\'ve moved your tabs from other devices into a panel on your home page that can be easily accessed every time you open a new tab.">
<!ENTITY remote_tabs_panel_moved_link "Take me to my new panel.">

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -6,45 +6,20 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto">
<ScrollView android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout android:id="@+id/private_tabs_empty"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:id="@+id/private_tabs_empty"
style="@style/PrivateTabsPanelFrame"
android:layout_width="@dimen/private_tabs_panel_empty_width"
android:layout_height="@dimen/private_tabs_panel_empty_height">
<!-- TODO: Remove the negative marginTop once we get rid of the
browser chrome at the bottom of the tabs tray.
Bug 1161638 -->
<ImageView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/private_masq"
android:layout_gravity="center"
android:layout_marginTop="-10dp"/>
<LinearLayout style="@style/TabsPanelSection.PrivateTabs.Header"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/private_tabs_empty_header"
style="@style/TabsPanelItem.TextAppearance.Header.PrivateTabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/private_browsing_title"/>
<TextView style="@style/TabsPanelItem.TextAppearance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/private_tabs_panel_empty_desc"/>
</LinearLayout>
<LinearLayout style="@style/TabsPanelSection.PrivateTabs"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/private_tabs_learn_more"
style="@style/TabsPanelItem.TextAppearance.Linkified.LearnMore"
android:layout_width="match_parent"
android:text="@string/private_tabs_panel_learn_more"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
</FrameLayout>
<!-- Note: for an unknown reason, scrolling in the TabsLayout
does not work unless it is laid out after the empty view. -->

View File

@ -19,34 +19,14 @@
</style>
<!-- Tabs panel -->
<style name="PrivateTabsPanelFrame">
<item name="android:paddingLeft">16dp</item>
<item name="android:paddingRight">16dp</item>
<item name="android:orientation">horizontal</item>
</style>
<style name="TabsPanelSection" parent="TabsPanelSectionBase">
<item name="android:layout_weight">1</item>
</style>
<style name="TabsPanelSection.PrivateTabs.Header">
<item name="android:paddingTop">10dp</item>
</style>
<style name="TabsPanelItem">
<item name="android:layout_marginBottom">20dp</item>
<item name="android:layout_gravity">left</item>
<item name="android:gravity">left</item>
</style>
<style name="TabsPanelItem.TextAppearance.Header.PrivateTabs">
<item name="android:visibility">gone</item>
</style>
<style name="TabsPanelItem.TextAppearance.Linkified.LearnMore">
<item name="android:layout_height">match_parent</item>
<item name="android:gravity">center</item>
<item name="android:layout_gravity">center</item>
</style>
</resources>

View File

@ -40,20 +40,8 @@
<item name="android:layout_marginRight">20dp</item>
</style>
<style name="TabsPanelSection.PrivateTabs">
<!-- We set values in tablet portrait. -->
</style>
<style name="TabsPanelSection.PrivateTabs.Header">
<!-- We set values in tablet portrait. -->
</style>
<style name="TabsPanelItem" parent="TabsPanelItemBase">
<!-- To override the values-land style. -->
</style>
<style name="TabsPanelItem.TextAppearance.Linkified.LearnMore">
<item name="android:layout_height">wrap_content</item>
</style>
</resources>

View File

@ -20,9 +20,6 @@
<dimen name="browser_toolbar_site_security_padding_vertical">21dp</dimen>
<dimen name="browser_toolbar_site_security_padding_horizontal">8dp</dimen>
<dimen name="private_tabs_panel_empty_width">300dp</dimen>
<dimen name="private_tabs_panel_empty_height">@dimen/wrap_content</dimen>
<dimen name="tabs_counter_size">26sp</dimen>
<dimen name="panel_grid_view_column_width">200dp</dimen>

View File

@ -126,36 +126,6 @@
<item name="android:paddingRight">32dp</item>
</style>
<!-- Tabs panel -->
<style name="PrivateTabsPanelFrame">
<item name="android:orientation">vertical</item>
<!-- We want to center the content on the screen, not in
the View, so add padding to compensate for the header. -->
<item name="android:layout_gravity">center</item>
<item name="android:paddingBottom">@dimen/browser_toolbar_height</item>
</style>
<style name="TabsPanelSection.PrivateTabs">
<item name="android:layout_weight">1</item>
<item name="android:layout_marginLeft">20dp</item>
<item name="android:layout_marginRight">20dp</item>
</style>
<style name="TabsPanelSection.PrivateTabs.Header">
<item name="android:paddingTop">10dp</item>
</style>
<style name="TabsPanelItem.TextAppearance.Header.PrivateTabs">
<item name="android:visibility">visible</item>
</style>
<style name="TabsPanelItem.TextAppearance.Linkified.LearnMore">
<item name="android:layout_height">match_parent</item>
<item name="android:gravity">center</item>
<item name="android:layout_gravity">center</item>
</style>
<style name="TextAppearance.UrlBar.Title" parent="TextAppearance.Medium">
<item name="android:textSize">16sp</item>
</style>

View File

@ -140,8 +140,6 @@
<dimen name="tabs_counter_size">22sp</dimen>
<dimen name="tabs_panel_indicator_width">60dp</dimen>
<dimen name="tabs_panel_list_padding">16dip</dimen>
<dimen name="private_tabs_panel_empty_width">@dimen/match_parent</dimen>
<dimen name="private_tabs_panel_empty_height">@dimen/match_parent</dimen>
<dimen name="tabs_list_divider_height">2dp</dimen>
<dimen name="tabs_strip_height">40dp</dimen>
<dimen name="tabs_strip_button_width">100dp</dimen>

View File

@ -520,13 +520,6 @@
</style>
<!-- Tabs panel -->
<style name="PrivateTabsPanelFrame">
<item name="android:paddingLeft">16dp</item>
<item name="android:paddingRight">16dp</item>
<item name="android:paddingTop">32dp</item>
<item name="android:orientation">vertical</item>
</style>
<style name="TabsPanelSectionBase">
<item name="android:orientation">vertical</item>
<item name="android:layout_marginLeft">40dp</item>
@ -537,14 +530,6 @@
<!-- We set values in landscape. -->
</style>
<style name="TabsPanelSection.PrivateTabs">
<!-- We set values on tablet. -->
</style>
<style name="TabsPanelSection.PrivateTabs.Header">
<!-- We set values on landscape and tablet. -->
</style>
<style name="TabsPanelItemBase">
<item name="android:layout_marginBottom">28dp</item>
<item name="android:layout_gravity">center</item>
@ -566,20 +551,12 @@
<item name="android:layout_marginBottom">16dp</item>
</style>
<style name="TabsPanelItem.TextAppearance.Header.PrivateTabs">
<!-- We change these values on landscape and tablet. -->
</style>
<style name="TabsPanelItem.TextAppearance.Linkified">
<item name="android:clickable">true</item>
<item name="android:focusable">true</item>
<item name="android:textColor">#0292D6</item>
</style>
<style name="TabsPanelItem.TextAppearance.Linkified.LearnMore">
<item name="android:layout_height">wrap_content</item>
</style>
<style name="Widget.RemoteTabsItemView" parent="Widget.TwoLinePageRow"/>
<style name="Widget.RemoteTabsClientView" parent="Widget.TwoLinePageRow">

View File

@ -418,11 +418,6 @@
<string name="home_remote_tabs_many_hidden_devices">&home_remote_tabs_many_hidden_devices;</string>
<string name="home_remote_tabs_hidden_devices_title">&home_remote_tabs_hidden_devices_title;</string>
<string name="home_remote_tabs_unhide_selected_devices">&home_remote_tabs_unhide_selected_devices;</string>
<string name="private_browsing_title">&private_browsing_title;</string>
<string name="private_tabs_panel_empty_desc">&private_tabs_panel_empty_desc;</string>
<string name="private_tabs_panel_learn_more">&private_tabs_panel_learn_more;</string>
<!-- https://support.mozilla.org/%LOCALE%/kb/mobile-private-browsing-browse-web-without-saving-syncing-info -->
<string name="private_tabs_panel_learn_more_link">https://support.mozilla.org/&formatS1;/kb/mobile-private-browsing-browse-web-without-saving-syncing-info</string>
<string name="pin_site_dialog_hint">&pin_site_dialog_hint;</string>
<string name="remote_tabs_panel_moved_title">&remote_tabs_panel_moved_title;</string>

View File

@ -5,11 +5,7 @@
package org.mozilla.gecko.tabs;
import java.util.Locale;
import org.mozilla.gecko.Locales;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.tabs.TabsPanel.CloseAllPanelView;
import org.mozilla.gecko.tabs.TabsPanel.TabsLayout;
@ -17,6 +13,7 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@ -27,8 +24,6 @@ import android.widget.LinearLayout;
* empty View's visibility.
*/
class PrivateTabsPanel extends FrameLayout implements CloseAllPanelView {
private TabsPanel tabsPanel;
private final TabsLayout tabsLayout;
public PrivateTabsPanel(Context context, AttributeSet attrs) {
@ -37,27 +32,12 @@ class PrivateTabsPanel extends FrameLayout implements CloseAllPanelView {
LayoutInflater.from(context).inflate(R.layout.private_tabs_panel, this);
tabsLayout = (TabsLayout) findViewById(R.id.private_tabs_layout);
final LinearLayout emptyTabsFrame = (LinearLayout) findViewById(R.id.private_tabs_empty);
final ViewGroup emptyTabsFrame = (ViewGroup) findViewById(R.id.private_tabs_empty);
tabsLayout.setEmptyView(emptyTabsFrame);
final View learnMore = findViewById(R.id.private_tabs_learn_more);
learnMore.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
final String locale = Locales.getLanguageTag(Locale.getDefault());
final String url =
getResources().getString(R.string.private_tabs_panel_learn_more_link, locale);
Tabs.getInstance().loadUrlInTab(url);
if (tabsPanel != null) {
tabsPanel.autoHidePanel();
}
}
});
}
@Override
public void setTabsPanel(TabsPanel panel) {
tabsPanel = panel;
tabsLayout.setTabsPanel(panel);
}

View File

@ -18,6 +18,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const NS_APP_CACHE_PARENT_DIR = "cachePDir";
const NS_APP_SEARCH_DIR = "SrchPlugns";
const NS_APP_SEARCH_DIR_LIST = "SrchPluginsDL";
const NS_APP_DISTRIBUTION_SEARCH_DIR_LIST = "SrchPluginsDistDL";
const NS_APP_USER_SEARCH_DIR = "UsrSrchPlugns";
const NS_XPCOM_CURRENT_PROCESS_DIR = "XCurProcD";
const XRE_APP_DISTRIBUTION_DIR = "XREAppDist";
@ -147,27 +148,32 @@ DirectoryProvider.prototype = {
},
getFiles: function(prop) {
if (prop != NS_APP_SEARCH_DIR_LIST)
return;
if (prop != NS_APP_SEARCH_DIR_LIST &&
prop != NS_APP_DISTRIBUTION_SEARCH_DIR_LIST)
return null;
let result = [];
/**
* We want to preserve the following order, since the search service loads
* engines in first-loaded-wins order.
* - distro search plugin locations
* - user search plugin locations (profile)
* - app search plugin location (shipped engines)
*/
this._appendDistroSearchDirs(result);
if (prop == NS_APP_DISTRIBUTION_SEARCH_DIR_LIST) {
this._appendDistroSearchDirs(result);
}
else {
/**
* We want to preserve the following order, since the search service
* loads engines in first-loaded-wins order.
* - distro search plugin locations (loaded separately by the search
* service)
* - user search plugin locations (profile)
* - app search plugin location (shipped engines)
*/
let appUserSearchDir = FileUtils.getDir(NS_APP_USER_SEARCH_DIR, [], false);
if (appUserSearchDir.exists())
result.push(appUserSearchDir);
let appUserSearchDir = FileUtils.getDir(NS_APP_USER_SEARCH_DIR, [], false);
if (appUserSearchDir.exists())
result.push(appUserSearchDir);
let appSearchDir = FileUtils.getDir(NS_APP_SEARCH_DIR, [], false);
if (appSearchDir.exists())
result.push(appSearchDir);
let appSearchDir = FileUtils.getDir(NS_APP_SEARCH_DIR, [], false);
if (appSearchDir.exists())
result.push(appSearchDir);
}
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),

View File

@ -51,6 +51,7 @@ const MODE_TRUNCATE = 0x20;
// Directory service keys
const NS_APP_SEARCH_DIR_LIST = "SrchPluginsDL";
const NS_APP_DISTRIBUTION_SEARCH_DIR_LIST = "SrchPluginsDistDL";
const NS_APP_USER_SEARCH_DIR = "UsrSrchPlugns";
const NS_APP_SEARCH_DIR = "SrchPlugns";
const NS_APP_USER_PROFILE_50_DIR = "ProfD";
@ -3485,8 +3486,7 @@ SearchService.prototype = {
cache = this._readCacheFile(cacheFile);
}
let loadDirs = [], chromeURIs = [], chromeFiles = [];
let chromeURIs = [], chromeFiles = [];
let loadFromJARs = false;
try {
loadFromJARs = Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF)
@ -3496,16 +3496,33 @@ SearchService.prototype = {
if (loadFromJARs)
[chromeFiles, chromeURIs] = this._findJAREngines();
let locations = getDir(NS_APP_SEARCH_DIR_LIST, Ci.nsISimpleEnumerator);
let distDirs = [];
let locations;
try {
locations = getDir(NS_APP_DISTRIBUTION_SEARCH_DIR_LIST,
Ci.nsISimpleEnumerator);
} catch (e) {
// NS_APP_DISTRIBUTION_SEARCH_DIR_LIST is defined by each app
// so this throws during unit tests (but not xpcshell tests).
locations = {hasMoreElements: () => false};
}
while (locations.hasMoreElements()) {
let dir = locations.getNext().QueryInterface(Ci.nsIFile);
if (dir.directoryEntries.hasMoreElements())
distDirs.push(dir);
}
let otherDirs = [];
locations = getDir(NS_APP_SEARCH_DIR_LIST, Ci.nsISimpleEnumerator);
while (locations.hasMoreElements()) {
let dir = locations.getNext().QueryInterface(Ci.nsIFile);
if (loadFromJARs && dir.equals(getDir(NS_APP_SEARCH_DIR)))
continue;
if (dir.directoryEntries.hasMoreElements())
loadDirs.push(dir);
otherDirs.push(dir);
}
let toLoad = chromeFiles.concat(loadDirs);
let toLoad = chromeFiles.concat(distDirs, otherDirs);
function modifiedDir(aDir) {
return (!cache.directories || !cache.directories[aDir.path] ||
@ -3528,10 +3545,12 @@ SearchService.prototype = {
if (!cacheEnabled || rebuildCache) {
LOG("_loadEngines: Absent or outdated cache. Loading engines from disk.");
loadDirs.forEach(this._loadEnginesFromDir, this);
distDirs.forEach(this._loadEnginesFromDir, this);
this._loadFromChromeURLs(chromeURIs);
otherDirs.forEach(this._loadEnginesFromDir, this);
if (cacheEnabled)
this._buildCache();
return;
@ -3561,8 +3580,7 @@ SearchService.prototype = {
cache = yield checkForSyncCompletion(this._asyncReadCacheFile(cacheFilePath));
}
let loadDirs = [], chromeURIs = [], chromeFiles = [];
let chromeURIs = [], chromeFiles = [];
let loadFromJARs = false;
try {
loadFromJARs = Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF)
@ -3575,21 +3593,25 @@ SearchService.prototype = {
yield checkForSyncCompletion(this._asyncFindJAREngines());
}
// Add the non-empty directories of NS_APP_SEARCH_DIR_LIST to
// loadDirs...
let locations = getDir(NS_APP_SEARCH_DIR_LIST, Ci.nsISimpleEnumerator);
// Get the non-empty distribution directories into distDirs...
let distDirs = [];
let locations;
try {
locations = getDir(NS_APP_DISTRIBUTION_SEARCH_DIR_LIST,
Ci.nsISimpleEnumerator);
} catch (e) {
// NS_APP_DISTRIBUTION_SEARCH_DIR_LIST is defined by each app
// so this throws during unit tests (but not xpcshell tests).
locations = {hasMoreElements: () => false};
}
while (locations.hasMoreElements()) {
let dir = locations.getNext().QueryInterface(Ci.nsIFile);
// ... but skip the application directory if we are loading from JAR.
if (loadFromJARs && dir.equals(getDir(NS_APP_SEARCH_DIR)))
continue;
let iterator = new OS.File.DirectoryIterator(dir.path,
{ winPattern: "*.xml" });
try {
// Add dir to loadDirs if it contains any files.
// Add dir to distDirs if it contains any files.
yield checkForSyncCompletion(iterator.next());
loadDirs.push(dir);
distDirs.push(dir);
} catch (ex if ex.result != Cr.NS_ERROR_ALREADY_INITIALIZED) {
// Catch for StopIteration exception.
} finally {
@ -3597,7 +3619,32 @@ SearchService.prototype = {
}
}
let toLoad = chromeFiles.concat(loadDirs);
// Add the non-empty directories of NS_APP_SEARCH_DIR_LIST to
// otherDirs...
let otherDirs = [];
locations = getDir(NS_APP_SEARCH_DIR_LIST, Ci.nsISimpleEnumerator);
while (locations.hasMoreElements()) {
let dir = locations.getNext().QueryInterface(Ci.nsIFile);
// ... but skip the application directory if we are loading from JAR.
// Applications shipping JAR engines don't ship plain text
// engine files anymore.
if (loadFromJARs && dir.equals(getDir(NS_APP_SEARCH_DIR)))
continue;
let iterator = new OS.File.DirectoryIterator(dir.path,
{ winPattern: "*.xml" });
try {
// Add dir to otherDirs if it contains any files.
yield checkForSyncCompletion(iterator.next());
otherDirs.push(dir);
} catch (ex if ex.result != Cr.NS_ERROR_ALREADY_INITIALIZED) {
// Catch for StopIteration exception.
} finally {
iterator.close();
}
}
let toLoad = chromeFiles.concat(distDirs, otherDirs);
function hasModifiedDir(aList) {
return Task.spawn(function() {
let modifiedDir = false;
@ -3636,7 +3683,7 @@ SearchService.prototype = {
if (!cacheEnabled || rebuildCache) {
LOG("_asyncLoadEngines: Absent or outdated cache. Loading engines from disk.");
let engines = [];
for (let loadDir of loadDirs) {
for (let loadDir of distDirs) {
let enginesFromDir =
yield checkForSyncCompletion(this._asyncLoadEnginesFromDir(loadDir));
engines = engines.concat(enginesFromDir);
@ -3644,6 +3691,11 @@ SearchService.prototype = {
let enginesFromURLs =
yield checkForSyncCompletion(this._asyncLoadFromChromeURLs(chromeURIs));
engines = engines.concat(enginesFromURLs);
for (let loadDir of otherDirs) {
let enginesFromDir =
yield checkForSyncCompletion(this._asyncLoadEnginesFromDir(loadDir));
engines = engines.concat(enginesFromDir);
}
for (let engine of engines) {
this._addEngineToStore(engine);

View File

@ -0,0 +1,8 @@
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>addon</ShortName>
<Description>addon</Description>
<InputEncoding>UTF-8</InputEncoding>
<Url type="text/html" method="GET" template="http://searchtest.local">
<Param name="search" value="{searchTerms}"/>
</Url>
</SearchPlugin>

View File

@ -0,0 +1,8 @@
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>bug645970</ShortName>
<Description>override</Description>
<InputEncoding>UTF-8</InputEncoding>
<Url type="text/html" method="GET" template="http://searchtest.local">
<Param name="search" value="{searchTerms}"/>
</Url>
</SearchPlugin>

View File

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>search-engine@tests.mozilla.org</em:id>
<em:unpack>true</em:unpack>
<em:version>1.0</em:version>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>Search Engine</em:name>
</Description>
</RDF>

View File

@ -96,6 +96,90 @@ function configureToLoadJarEngines(loadFromJars = true)
do_get_file("data/engine-app.xml").copyTo(dir, "app.xml");
}
/**
* Fake the installation of an add-on in the profile, by creating the
* directory and registering it with the directory service.
*/
function installAddonEngine(name = "engine-addon")
{
const XRE_EXTENSIONS_DIR_LIST = "XREExtDL";
const gProfD = do_get_profile().QueryInterface(Ci.nsILocalFile);
let dir = gProfD.clone();
dir.append("extensions");
if (!dir.exists())
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
dir.append("search-engine@tests.mozilla.org");
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
do_get_file("data/install.rdf").copyTo(dir, "install.rdf");
let addonDir = dir.clone();
dir.append("searchplugins");
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
do_get_file("data/" + name + ".xml").copyTo(dir, "bug645970.xml");
Services.dirsvc.registerProvider({
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider,
Ci.nsIDirectoryServiceProvider2]),
getFile: function (prop, persistant) {
throw Cr.NS_ERROR_FAILURE;
},
getFiles: function (prop) {
let result = [];
switch (prop) {
case XRE_EXTENSIONS_DIR_LIST:
result.push(addonDir);
break;
default:
throw Cr.NS_ERROR_FAILURE;
}
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
hasMoreElements: () => result.length > 0,
getNext: () => result.shift()
};
}
});
}
/**
* Copy the engine-distribution.xml engine to a fake distribution
* created in the profile, and registered with the directory service.
*/
function installDistributionEngine()
{
const XRE_APP_DISTRIBUTION_DIR = "XREAppDist";
const gProfD = do_get_profile().QueryInterface(Ci.nsILocalFile);
let dir = gProfD.clone();
dir.append("distribution");
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
let distDir = dir.clone();
dir.append("searchplugins");
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
dir.append("common");
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
do_get_file("data/engine-override.xml").copyTo(dir, "bug645970.xml");
Services.dirsvc.registerProvider({
getFile: function(aProp, aPersistent) {
aPersistent.value = true;
if (aProp == XRE_APP_DISTRIBUTION_DIR)
return distDir.clone();
return null;
}
});
}
/**
* Clean the profile of any metadata files left from a previous run.
*/

View File

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
do_test_pending();
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
configureToLoadJarEngines();
installAddonEngine();
do_check_false(Services.search.isInitialized);
Services.search.init(function search_initialized(aStatus) {
do_check_true(Components.isSuccessCode(aStatus));
do_check_true(Services.search.isInitialized);
// test the add-on engine is loaded in addition to our jar engine
let engines = Services.search.getEngines();
do_check_eq(engines.length, 2);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("addon");
do_check_neq(engine, null);
do_check_eq(engine.description, "addon");
do_test_finished();
});
}

View File

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
do_test_pending();
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
configureToLoadJarEngines();
installAddonEngine("engine-override");
do_check_false(Services.search.isInitialized);
Services.search.init(function search_initialized(aStatus) {
do_check_true(Components.isSuccessCode(aStatus));
do_check_true(Services.search.isInitialized);
// test the add-on engine isn't overriding our jar engine
let engines = Services.search.getEngines();
do_check_eq(engines.length, 1);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
do_check_eq(engine.description, "bug645970");
do_test_finished();
});
}

View File

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
do_test_pending();
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
configureToLoadJarEngines();
installDistributionEngine();
do_check_false(Services.search.isInitialized);
Services.search.init(function search_initialized(aStatus) {
do_check_true(Components.isSuccessCode(aStatus));
do_check_true(Services.search.isInitialized);
// test that the engine from the distribution overrides our jar engine
let engines = Services.search.getEngines();
do_check_eq(engines.length, 1);
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
// check the engine we have is actually the one from the distribution
do_check_eq(engine.description, "override");
do_test_finished();
});
}

View File

@ -0,0 +1,42 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const NS_APP_USER_SEARCH_DIR = "UsrSrchPlugns";
function run_test() {
do_test_pending();
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
configureToLoadJarEngines();
// Copy an engine in [profile]/searchplugin/ and ensure it's not
// overriding the same file from a jar.
// The description in the file we are copying is 'profile'.
let dir = Services.dirsvc.get(NS_APP_USER_SEARCH_DIR, Ci.nsIFile);
if (!dir.exists())
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
do_get_file("data/engine-override.xml").copyTo(dir, "bug645970.xml");
do_check_false(Services.search.isInitialized);
Services.search.init(function search_initialized(aStatus) {
do_check_true(Components.isSuccessCode(aStatus));
do_check_true(Services.search.isInitialized);
// test engines from dir are not loaded.
let engines = Services.search.getEngines();
do_check_eq(engines.length, 1);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
do_check_eq(engine.description, "bug645970");
do_test_finished();
});
}

View File

@ -0,0 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
configureToLoadJarEngines();
installAddonEngine();
do_check_false(Services.search.isInitialized);
// test the add-on engine is loaded in addition to our jar engine
let engines = Services.search.getEngines();
do_check_eq(engines.length, 2);
do_check_true(Services.search.isInitialized);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("addon");
do_check_neq(engine, null);
do_check_eq(engine.description, "addon");
}

View File

@ -0,0 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
configureToLoadJarEngines();
installAddonEngine("engine-override");
do_check_false(Services.search.isInitialized);
// test the add-on engine isn't overriding our jar engine
let engines = Services.search.getEngines();
do_check_eq(engines.length, 1);
do_check_true(Services.search.isInitialized);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
do_check_eq(engine.description, "bug645970");
}

View File

@ -0,0 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
configureToLoadJarEngines();
installDistributionEngine();
do_check_false(Services.search.isInitialized);
// test that the engine from the distribution overrides our jar engine
let engines = Services.search.getEngines();
do_check_eq(engines.length, 1);
do_check_true(Services.search.isInitialized);
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
// check the engine we have is actually the one from the distribution
do_check_eq(engine.description, "override");
}

View File

@ -0,0 +1,35 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const NS_APP_USER_SEARCH_DIR = "UsrSrchPlugns";
function run_test() {
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
configureToLoadJarEngines();
// Copy an engine in [profile]/searchplugin/ and ensure it's not
// overriding the same file from a jar.
// The description in the file we are copying is 'profile'.
let dir = Services.dirsvc.get(NS_APP_USER_SEARCH_DIR, Ci.nsIFile);
if (!dir.exists())
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
do_get_file("data/engine-override.xml").copyTo(dir, "bug645970.xml");
do_check_false(Services.search.isInitialized);
// test engines from dir are not loaded.
let engines = Services.search.getEngines();
do_check_eq(engines.length, 1);
do_check_true(Services.search.isInitialized);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
do_check_eq(engine.description, "bug645970");
}

View File

@ -8,6 +8,8 @@ support-files =
data/engine.src
data/engine.xml
data/engine2.xml
data/engine-addon.xml
data/engine-override.xml
data/engine-app.xml
data/engine-fr.xml
data/engineMaker.sjs
@ -17,6 +19,7 @@ support-files =
data/engineImages.xml
data/ico-size-16x16-png.ico
data/invalid-engine.xml
data/install.rdf
data/search-metadata.json
data/search.json
data/search.sqlite
@ -58,9 +61,17 @@ support-files =
[test_searchSuggest.js]
[test_async.js]
[test_async_app.js]
[test_async_addon.js]
[test_async_addon_no_override.js]
[test_async_distribution.js]
[test_async_profile_engine.js]
[test_sync.js]
[test_sync_app.js]
[test_sync_addon.js]
[test_sync_addon_no_override.js]
[test_sync_distribution.js]
[test_sync_fallback.js]
[test_sync_delay_fallback.js]
[test_sync_profile_engine.js]
[test_rel_searchform.js]
[test_selectedEngine.js]

View File

@ -112,9 +112,9 @@ exports.items = [
}],
exec: function*(args, context) {
if (!args.chrome) {
const value = yield context.updateExec("paintflashing_server --state on");
isContentPaintFlashing = value;
onPaintFlashingChanged(context.environment.target, value);
const output = yield context.updateExec("paintflashing_server --state on");
isContentPaintFlashing = output.data;
onPaintFlashingChanged(context.environment.target, output.data);
}
else {
setPaintFlashing(context.environment.chromeWindow, "on");
@ -142,9 +142,9 @@ exports.items = [
}],
exec: function*(args, context) {
if (!args.chrome) {
const value = yield context.updateExec("paintflashing_server --state off");
isContentPaintFlashing = value;
onPaintFlashingChanged(context.environment.target, value);
const output = yield context.updateExec("paintflashing_server --state off");
isContentPaintFlashing = output.data;
onPaintFlashingChanged(context.environment.target, output.data);
}
else {
setPaintFlashing(context.environment.chromeWindow, "off");
@ -167,9 +167,9 @@ exports.items = [
description: l10n.lookup("paintflashingToggleDesc"),
manual: l10n.lookup("paintflashingManual"),
exec: function*(args, context) {
const value = yield context.updateExec("paintflashing_server --state toggle");
isContentPaintFlashing = value;
onPaintFlashingChanged(context.environment.target, value);
const output = yield context.updateExec("paintflashing_server --state toggle");
isContentPaintFlashing = output.data;
onPaintFlashingChanged(context.environment.target, output.data);
}
},
{

View File

@ -201,6 +201,8 @@ Moving right along, let's say you want to pass/return an array of Incrementors.
response: { incrementors: RetVal("array:incrementor") }
})
You can use an iterator in place of an array as an argument or return value, and the library will handle the conversion automatically.
Or maybe you want to return a dictionary where one item is a incrementor. To do this you need to tell the type system which members of the dictionary need custom marshallers:
protocol.types.addDictType("contrivedObject", {

View File

@ -109,6 +109,11 @@ function identityWrite(v) {
if (v === undefined) {
throw Error("undefined passed where a value is required");
}
// This has to handle iterator->array conversion because arrays of
// primitive types pass through here.
if (v && typeof (v) === "object" && Symbol.iterator in v) {
return [...v];
}
return v;
}
@ -190,8 +195,8 @@ types.addArrayType = function(subtype) {
}
return types.addType(name, {
category: "array",
read: (v, ctx) => v.map(i => subtype.read(i, ctx)),
write: (v, ctx) => v.map(i => subtype.write(i, ctx))
read: (v, ctx) => [...v].map(i => subtype.read(i, ctx)),
write: (v, ctx) => [...v].map(i => subtype.write(i, ctx))
});
};

View File

@ -82,6 +82,19 @@ let ChildActor = protocol.ActorClass({
}
}),
getIntArray: method(function(inputArray) {
// Test that protocol.js converts an iterator to an array.
let f = function*() {
for (let i of inputArray) {
yield 2 * i;
}
};
return f();
}, {
request: { inputArray: Arg(0, "array:number") },
response: RetVal("array:number")
}),
getSibling: method(function(id) {
return this.parent().getChild(id);
}, {
@ -193,6 +206,18 @@ let RootActor = protocol.ActorClass({
response: { children: RetVal("array:childActor") },
}),
getChildren2: method(function(ids) {
let f = function*() {
for (let c of ids) {
yield c;
}
};
return f();
}, {
request: { ids: Arg(0, "array:childActor") },
response: { children: RetVal("array:childActor") },
}),
getManyChildren: method(function() {
return {
foo: "bar", // note that this isn't in the specialization array.
@ -441,6 +466,34 @@ function run_test()
do_check_eq(ret.child5.childID, "child5");
do_check_eq(ret.more[0].childID, "child6");
do_check_eq(ret.more[1].childID, "child7");
}).then(() => {
// Test accepting a generator.
let f = function*() {
for (let i of [1, 2, 3, 4, 5]) {
yield i;
}
};
return childFront.getIntArray(f());
}).then((ret) => {
do_check_eq(ret.length, 5);
let expected = [2, 4, 6, 8, 10];
for (let i = 0; i < 5; ++i) {
do_check_eq(ret[i], expected[i]);
}
}).then(() => {
return rootFront.getChildren(["child1", "child2"]);
}).then(ids => {
let f = function*() {
for (let id of ids) {
yield id;
}
};
return rootFront.getChildren2(f());
}).then(ret => {
do_check_eq(ret.length, 2);
do_check_true(ret[0] === childFront);
do_check_true(ret[1] !== childFront);
do_check_true(ret[1] instanceof ChildFront);
}).then(() => {
client.close(() => {
do_test_finished();

View File

@ -48,6 +48,7 @@
#define NS_APP_CHROME_DIR_LIST "AChromDL"
#define NS_APP_PLUGINS_DIR_LIST "APluginsDL"
#define NS_APP_SEARCH_DIR_LIST "SrchPluginsDL"
#define NS_APP_DISTRIBUTION_SEARCH_DIR_LIST "SrchPluginsDistDL"
// --------------------------------------------------------------------------------------
// Files and directories which exist on a per-profile basis