mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-24 11:27:49 +00:00
Merge fx-team to m-c
This commit is contained in:
commit
edf79e60e0
@ -9,7 +9,11 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_observableobject.js \
|
||||
browser_layoutHelpers.js \
|
||||
browser_require_basic.js \
|
||||
browser_telemetry_buttonsandsidebar.js \
|
||||
browser_telemetry_sidebar.js \
|
||||
browser_telemetry_button_responsive.js \
|
||||
browser_telemetry_button_scratchpad.js \
|
||||
browser_telemetry_button_tilt.js \
|
||||
browser_telemetry_button_paintflashing.js \
|
||||
browser_telemetry_toolboxtabs_inspector.js \
|
||||
browser_telemetry_toolboxtabs_jsdebugger.js \
|
||||
browser_telemetry_toolboxtabs_jsprofiler.js \
|
||||
|
@ -0,0 +1,127 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_paintflashing.js</p>";
|
||||
|
||||
// Because we need to gather stats for the period of time that a tool has been
|
||||
// opened we make use of setTimeout() to create tool active times.
|
||||
const TOOL_DELAY = 200;
|
||||
|
||||
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
|
||||
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
let Telemetry = require("devtools/shared/telemetry");
|
||||
|
||||
function init() {
|
||||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
}
|
||||
|
||||
this.telemetryInfo[histogramId].push(value);
|
||||
}
|
||||
};
|
||||
|
||||
testButton("command-button-paintflashing");
|
||||
}
|
||||
|
||||
function testButton(id) {
|
||||
info("Testing " + id);
|
||||
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
info("inspector opened");
|
||||
|
||||
let button = toolbox.doc.querySelector("#" + id);
|
||||
ok(button, "Captain, we have the button");
|
||||
|
||||
delayedClicks(button, 4).then(function() {
|
||||
checkResults("_PAINTFLASHING_");
|
||||
});
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function delayedClicks(node, clicks) {
|
||||
let deferred = promise.defer();
|
||||
let clicked = 0;
|
||||
|
||||
// See TOOL_DELAY for why we need setTimeout here
|
||||
setTimeout(function delayedClick() {
|
||||
info("Clicking button " + node.id);
|
||||
node.click();
|
||||
clicked++;
|
||||
|
||||
if (clicked >= clicks) {
|
||||
deferred.resolve(node);
|
||||
} else {
|
||||
setTimeout(delayedClick, TOOL_DELAY);
|
||||
}
|
||||
}, TOOL_DELAY);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkResults(histIdFocus) {
|
||||
let result = Telemetry.prototype.telemetryInfo;
|
||||
|
||||
for (let [histId, value] of Iterator(result)) {
|
||||
if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
|
||||
!histId.contains(histIdFocus)) {
|
||||
// Inspector stats are tested in
|
||||
// browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
|
||||
// because we only open the inspector once for this test.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element === true;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries are === true");
|
||||
} else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element > 0;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries have time > 0");
|
||||
}
|
||||
}
|
||||
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
Telemetry.prototype.log = Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype.telemetryInfo;
|
||||
|
||||
TargetFactory = Services = promise = require = null;
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
waitForFocus(init, content);
|
||||
}, true);
|
||||
|
||||
content.location = TEST_URI;
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_responsive.js</p>";
|
||||
|
||||
// Because we need to gather stats for the period of time that a tool has been
|
||||
// opened we make use of setTimeout() to create tool active times.
|
||||
const TOOL_DELAY = 200;
|
||||
|
||||
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
|
||||
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
let Telemetry = require("devtools/shared/telemetry");
|
||||
|
||||
function init() {
|
||||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
}
|
||||
|
||||
this.telemetryInfo[histogramId].push(value);
|
||||
}
|
||||
};
|
||||
|
||||
testButton("command-button-responsive");
|
||||
}
|
||||
|
||||
function testButton(id) {
|
||||
info("Testing " + id);
|
||||
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
info("inspector opened");
|
||||
|
||||
let button = toolbox.doc.querySelector("#" + id);
|
||||
ok(button, "Captain, we have the button");
|
||||
|
||||
delayedClicks(button, 4).then(function() {
|
||||
checkResults("_RESPONSIVE_");
|
||||
});
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function delayedClicks(node, clicks) {
|
||||
let deferred = promise.defer();
|
||||
let clicked = 0;
|
||||
|
||||
// See TOOL_DELAY for why we need setTimeout here
|
||||
setTimeout(function delayedClick() {
|
||||
info("Clicking button " + node.id);
|
||||
node.click();
|
||||
clicked++;
|
||||
|
||||
if (clicked >= clicks) {
|
||||
deferred.resolve(node);
|
||||
} else {
|
||||
setTimeout(delayedClick, TOOL_DELAY);
|
||||
}
|
||||
}, TOOL_DELAY);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkResults(histIdFocus) {
|
||||
let result = Telemetry.prototype.telemetryInfo;
|
||||
|
||||
for (let [histId, value] of Iterator(result)) {
|
||||
if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
|
||||
!histId.contains(histIdFocus)) {
|
||||
// Inspector stats are tested in
|
||||
// browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
|
||||
// because we only open the inspector once for this test.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element === true;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries are === true");
|
||||
} else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element > 0;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries have time > 0");
|
||||
}
|
||||
}
|
||||
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
Telemetry.prototype.log = Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype.telemetryInfo;
|
||||
|
||||
TargetFactory = Services = promise = require = null;
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
waitForFocus(init, content);
|
||||
}, true);
|
||||
|
||||
content.location = TEST_URI;
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_scratchpad.js</p>";
|
||||
|
||||
// Because we need to gather stats for the period of time that a tool has been
|
||||
// opened we make use of setTimeout() to create tool active times.
|
||||
const TOOL_DELAY = 200;
|
||||
|
||||
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
|
||||
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
let Telemetry = require("devtools/shared/telemetry");
|
||||
|
||||
let numScratchpads = 0;
|
||||
|
||||
function init() {
|
||||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
}
|
||||
|
||||
this.telemetryInfo[histogramId].push(value);
|
||||
}
|
||||
};
|
||||
|
||||
Services.ww.registerNotification(windowObserver);
|
||||
testButton("command-button-scratchpad");
|
||||
}
|
||||
|
||||
function testButton(id) {
|
||||
info("Testing " + id);
|
||||
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
info("inspector opened");
|
||||
|
||||
let button = toolbox.doc.querySelector("#" + id);
|
||||
ok(button, "Captain, we have the button");
|
||||
|
||||
delayedClicks(button, 4).then(null, console.error);
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function windowObserver(aSubject, aTopic, aData) {
|
||||
if (aTopic == "domwindowopened") {
|
||||
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
||||
win.addEventListener("load", function onLoad() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
|
||||
if (win.Scratchpad) {
|
||||
win.Scratchpad.addObserver({
|
||||
onReady: function() {
|
||||
win.Scratchpad.removeObserver(this);
|
||||
numScratchpads++;
|
||||
win.close();
|
||||
|
||||
info("another scratchpad was opened and closed, count is now " + numScratchpads);
|
||||
|
||||
if (numScratchpads === 4) {
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
info("4 scratchpads have been opened and closed, checking results");
|
||||
checkResults("_SCRATCHPAD_");
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
|
||||
function delayedClicks(node, clicks) {
|
||||
let deferred = promise.defer();
|
||||
let clicked = 0;
|
||||
|
||||
// See TOOL_DELAY for why we need setTimeout here
|
||||
setTimeout(function delayedClick() {
|
||||
info("Clicking button " + node.id);
|
||||
node.click();
|
||||
clicked++;
|
||||
|
||||
if (clicked >= clicks) {
|
||||
deferred.resolve(node);
|
||||
} else {
|
||||
setTimeout(delayedClick, TOOL_DELAY);
|
||||
}
|
||||
}, TOOL_DELAY);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkResults(histIdFocus) {
|
||||
let result = Telemetry.prototype.telemetryInfo;
|
||||
|
||||
for (let [histId, value] of Iterator(result)) {
|
||||
if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
|
||||
!histId.contains(histIdFocus)) {
|
||||
// Inspector stats are tested in
|
||||
// browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
|
||||
// because we only open the inspector once for this test.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element === true;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries are === true");
|
||||
} else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element > 0;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries have time > 0");
|
||||
}
|
||||
}
|
||||
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
Telemetry.prototype.log = Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype.telemetryInfo;
|
||||
|
||||
TargetFactory = Services = promise = require = numScratchpads = null;
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
waitForFocus(init, content);
|
||||
}, true);
|
||||
|
||||
content.location = TEST_URI;
|
||||
}
|
127
browser/devtools/shared/test/browser_telemetry_button_tilt.js
Normal file
127
browser/devtools/shared/test/browser_telemetry_button_tilt.js
Normal file
@ -0,0 +1,127 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_tilt.js</p>";
|
||||
|
||||
// Because we need to gather stats for the period of time that a tool has been
|
||||
// opened we make use of setTimeout() to create tool active times.
|
||||
const TOOL_DELAY = 200;
|
||||
|
||||
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
|
||||
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
let Telemetry = require("devtools/shared/telemetry");
|
||||
|
||||
function init() {
|
||||
Telemetry.prototype.telemetryInfo = {};
|
||||
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||
Telemetry.prototype.log = function(histogramId, value) {
|
||||
if (histogramId) {
|
||||
if (!this.telemetryInfo[histogramId]) {
|
||||
this.telemetryInfo[histogramId] = [];
|
||||
}
|
||||
|
||||
this.telemetryInfo[histogramId].push(value);
|
||||
}
|
||||
};
|
||||
|
||||
testButton("command-button-tilt");
|
||||
}
|
||||
|
||||
function testButton(id) {
|
||||
info("Testing " + id);
|
||||
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
info("inspector opened");
|
||||
|
||||
let button = toolbox.doc.querySelector("#" + id);
|
||||
ok(button, "Captain, we have the button");
|
||||
|
||||
delayedClicks(button, 4).then(function() {
|
||||
checkResults("_TILT_");
|
||||
});
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function delayedClicks(node, clicks) {
|
||||
let deferred = promise.defer();
|
||||
let clicked = 0;
|
||||
|
||||
// See TOOL_DELAY for why we need setTimeout here
|
||||
setTimeout(function delayedClick() {
|
||||
info("Clicking button " + node.id);
|
||||
node.click();
|
||||
clicked++;
|
||||
|
||||
if (clicked >= clicks) {
|
||||
deferred.resolve(node);
|
||||
} else {
|
||||
setTimeout(delayedClick, TOOL_DELAY);
|
||||
}
|
||||
}, TOOL_DELAY);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkResults(histIdFocus) {
|
||||
let result = Telemetry.prototype.telemetryInfo;
|
||||
|
||||
for (let [histId, value] of Iterator(result)) {
|
||||
if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
|
||||
!histId.contains(histIdFocus)) {
|
||||
// Inspector stats are tested in
|
||||
// browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
|
||||
// because we only open the inspector once for this test.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element === true;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries are === true");
|
||||
} else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
return element > 0;
|
||||
});
|
||||
|
||||
ok(okay, "All " + histId + " entries have time > 0");
|
||||
}
|
||||
}
|
||||
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
Telemetry.prototype.log = Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype._oldlog;
|
||||
delete Telemetry.prototype.telemetryInfo;
|
||||
|
||||
TargetFactory = Services = promise = require = null;
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
waitForFocus(init, content);
|
||||
}, true);
|
||||
|
||||
content.location = TEST_URI;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_buttonsandsidebar.js</p>";
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_sidebar.js</p>";
|
||||
|
||||
// Because we need to gather stats for the period of time that a tool has been
|
||||
// opened we make use of setTimeout() to create tool active times.
|
||||
@ -24,66 +24,9 @@ function init() {
|
||||
|
||||
this.telemetryInfo[histogramId].push(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
testButtons();
|
||||
}
|
||||
|
||||
function testButtons() {
|
||||
info("Testing buttons");
|
||||
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
let container = toolbox.doc.getElementById("toolbox-buttons");
|
||||
let buttons = container.getElementsByTagName("toolbarbutton");
|
||||
|
||||
// Copy HTMLCollection to array.
|
||||
buttons = Array.prototype.slice.call(buttons);
|
||||
|
||||
(function testButton() {
|
||||
let button = buttons.pop();
|
||||
|
||||
if (button) {
|
||||
info("Clicking button " + button.id);
|
||||
button.click();
|
||||
delayedClicks(button, 3).then(function(button) {
|
||||
if (buttons.length == 0) {
|
||||
// Remove scratchpads
|
||||
let wins = Services.wm.getEnumerator("devtools:scratchpad");
|
||||
while (wins.hasMoreElements()) {
|
||||
let win = wins.getNext();
|
||||
info("Closing scratchpad window");
|
||||
win.close();
|
||||
}
|
||||
|
||||
testSidebar();
|
||||
} else {
|
||||
setTimeout(testButton, TOOL_DELAY);
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
}).then(null, reportError);
|
||||
}
|
||||
|
||||
function delayedClicks(node, clicks) {
|
||||
let deferred = promise.defer();
|
||||
let clicked = 0;
|
||||
|
||||
setTimeout(function delayedClick() {
|
||||
info("Clicking button " + node.id);
|
||||
node.click();
|
||||
clicked++;
|
||||
|
||||
if (clicked >= clicks) {
|
||||
deferred.resolve(node);
|
||||
} else {
|
||||
setTimeout(delayedClick, TOOL_DELAY);
|
||||
}
|
||||
}, TOOL_DELAY);
|
||||
|
||||
return deferred.promise;
|
||||
testSidebar();
|
||||
}
|
||||
|
||||
function testSidebar() {
|
||||
@ -98,6 +41,7 @@ function testSidebar() {
|
||||
// Concatenate the array with itself so that we can open each tool twice.
|
||||
sidebarTools.push.apply(sidebarTools, sidebarTools);
|
||||
|
||||
// See TOOL_DELAY for why we need setTimeout here
|
||||
setTimeout(function selectSidebarTab() {
|
||||
let tool = sidebarTools.pop();
|
||||
if (tool) {
|
||||
@ -147,14 +91,6 @@ function checkResults() {
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function reportError(error) {
|
||||
let stack = " " + error.stack.replace(/\n?.*?@/g, "\n JS frame :: ");
|
||||
|
||||
ok(false, "ERROR: " + error + " at " + error.fileName + ":" +
|
||||
error.lineNumber + "\n\nStack trace:" + stack);
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
gBrowser.removeCurrentTab();
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||
|
||||
/**
|
||||
* Open a new tab at a URL and call a callback on load
|
||||
|
@ -403,7 +403,9 @@ NS_IMETHODIMP nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword,
|
||||
// the search engine's name through various function calls.
|
||||
nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
|
||||
if (obsSvc) {
|
||||
obsSvc->NotifyObservers(defaultEngine, "keyword-search", NS_ConvertUTF8toUTF16(keyword).get());
|
||||
// Note that "keyword-search" refers to a search via the url
|
||||
// bar, not a bookmarks keyword search.
|
||||
obsSvc->NotifyObservers(defaultEngine, "keyword-search", NS_ConvertUTF8toUTF16(keyword).get());
|
||||
}
|
||||
|
||||
return submission->GetUri(aURI);
|
||||
|
@ -729,8 +729,8 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
||||
// the page is zoomed in, the frame's size might be larger than the widget
|
||||
// bounds, but we don't want the composition bounds to be.
|
||||
bool useWidgetBounds = false;
|
||||
bool isRootContentDocRootScrollFrame = aForFrame->GetParent() == nullptr
|
||||
&& presContext->IsRootContentDocument();
|
||||
bool isRootContentDocRootScrollFrame = presContext->IsRootContentDocument()
|
||||
&& aScrollFrame == presShell->GetRootScrollFrame();
|
||||
if (isRootContentDocRootScrollFrame) {
|
||||
if (nsIWidget* widget = aForFrame->GetNearestWidget()) {
|
||||
nsIntRect bounds;
|
||||
|
@ -1444,7 +1444,8 @@ abstract public class BrowserApp extends GeckoApp
|
||||
|
||||
final String keywordUrl = BrowserDB.getUrlForKeyword(getContentResolver(), keyword);
|
||||
|
||||
// If there isn't a bookmark keyword, just load the URL.
|
||||
// If there isn't a bookmark keyword, load the url. This may result in a query
|
||||
// using the default search engine.
|
||||
if (TextUtils.isEmpty(keywordUrl)) {
|
||||
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
|
||||
return;
|
||||
|
@ -194,6 +194,7 @@ FENNEC_JAVA_FILES = \
|
||||
gfx/LayerView.java \
|
||||
gfx/NativePanZoomController.java \
|
||||
gfx/NinePatchTileLayer.java \
|
||||
gfx/Overscroll.java \
|
||||
gfx/PanningPerfAPI.java \
|
||||
gfx/PanZoomController.java \
|
||||
gfx/PanZoomTarget.java \
|
||||
|
@ -154,6 +154,10 @@ abstract class Axis {
|
||||
mRecentVelocities = new float[FLING_VELOCITY_POINTS];
|
||||
}
|
||||
|
||||
// Implementors can override these to show effects when the axis overscrolls
|
||||
protected void overscrollFling(float velocity) { }
|
||||
protected void overscrollPan(float displacement) { }
|
||||
|
||||
public void setOverScrollMode(int overscrollMode) {
|
||||
mOverscrollMode = overscrollMode;
|
||||
}
|
||||
@ -379,12 +383,22 @@ abstract class Axis {
|
||||
// getOverscroll which doesn't take into account any new displacment being applied.
|
||||
// If we using a subscroller, we don't want to alter the scrolling being done
|
||||
if (getOverScrollMode() == View.OVER_SCROLL_NEVER && !mSubscroller.scrolling()) {
|
||||
float originalDisplacement = mDisplacement;
|
||||
|
||||
if (mDisplacement + getOrigin() < getPageStart() - getMarginStart()) {
|
||||
mDisplacement = getPageStart() - getMarginStart() - getOrigin();
|
||||
stopFling();
|
||||
} else if (mDisplacement + getViewportEnd() > getPageEnd() + getMarginEnd()) {
|
||||
mDisplacement = getPageEnd() - getMarginEnd() - getViewportEnd();
|
||||
stopFling();
|
||||
}
|
||||
|
||||
// Return the amount of overscroll so that the overscroll controller can draw it for us
|
||||
if (originalDisplacement != mDisplacement) {
|
||||
if (mFlingState == FlingStates.FLINGING) {
|
||||
overscrollFling(mVelocity / MS_PER_FRAME * 1000);
|
||||
stopFling();
|
||||
} else if (mFlingState == FlingStates.PANNING) {
|
||||
overscrollPan(originalDisplacement - mDisplacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,6 +132,10 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
|
||||
mContentDocumentIsDisplayed = true;
|
||||
}
|
||||
|
||||
public void setOverscrollHandler(final Overscroll listener) {
|
||||
mPanZoomController.setOverscrollHandler(listener);
|
||||
}
|
||||
|
||||
/** Attaches to root layer so that Gecko appears. */
|
||||
public void notifyGeckoReady() {
|
||||
mGeckoIsReady = true;
|
||||
|
@ -129,6 +129,9 @@ class JavaPanZoomController
|
||||
/* Used to change the scrollY direction */
|
||||
private boolean mNegateWheelScrollY;
|
||||
|
||||
// Handler to be notified when overscroll occurs
|
||||
private Overscroll mOverscroll;
|
||||
|
||||
public JavaPanZoomController(PanZoomTarget target, View view, EventDispatcher eventDispatcher) {
|
||||
mTarget = target;
|
||||
mSubscroller = new SubdocumentScrollHelper(eventDispatcher);
|
||||
@ -1113,6 +1116,18 @@ class JavaPanZoomController
|
||||
RectF maxMargins = mTarget.getMaxMargins();
|
||||
return (metrics.marginLeft < maxMargins.left || metrics.marginRight < maxMargins.right);
|
||||
}
|
||||
@Override
|
||||
protected void overscrollFling(final float velocity) {
|
||||
if (mOverscroll != null) {
|
||||
mOverscroll.setVelocity(velocity, Overscroll.Axis.X);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void overscrollPan(final float distance) {
|
||||
if (mOverscroll != null) {
|
||||
mOverscroll.setDistance(distance, Overscroll.Axis.X);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AxisY extends Axis {
|
||||
@ -1135,6 +1150,18 @@ class JavaPanZoomController
|
||||
RectF maxMargins = mTarget.getMaxMargins();
|
||||
return (metrics.marginTop < maxMargins.top || metrics.marginBottom < maxMargins.bottom);
|
||||
}
|
||||
@Override
|
||||
protected void overscrollFling(final float velocity) {
|
||||
if (mOverscroll != null) {
|
||||
mOverscroll.setVelocity(velocity, Overscroll.Axis.Y);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void overscrollPan(final float distance) {
|
||||
if (mOverscroll != null) {
|
||||
mOverscroll.setDistance(distance, Overscroll.Axis.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1434,4 +1461,9 @@ class JavaPanZoomController
|
||||
public void updateScrollOffset(float cssX, float cssY) {
|
||||
// Nothing to update, this class doesn't store the scroll offset locally.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverscrollHandler(final Overscroll handler) {
|
||||
mOverscroll = handler;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import org.mozilla.gecko.util.EventDispatcher;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PointF;
|
||||
@ -67,6 +68,7 @@ public class LayerView extends FrameLayout {
|
||||
|
||||
/* This should only be modified on the Java UI thread. */
|
||||
private final ArrayList<TouchEventInterceptor> mTouchInterceptors;
|
||||
private final Overscroll mOverscroll;
|
||||
|
||||
/* Flags used to determine when to show the painted surface. */
|
||||
public static final int PAINT_START = 0;
|
||||
@ -104,10 +106,13 @@ public class LayerView extends FrameLayout {
|
||||
mBackgroundColor = Color.WHITE;
|
||||
|
||||
mTouchInterceptors = new ArrayList<TouchEventInterceptor>();
|
||||
mOverscroll = new Overscroll(this);
|
||||
}
|
||||
|
||||
public void initializeView(EventDispatcher eventDispatcher) {
|
||||
mLayerClient = new GeckoLayerClient(getContext(), this, eventDispatcher);
|
||||
mLayerClient.setOverscrollHandler(mOverscroll);
|
||||
|
||||
mPanZoomController = mLayerClient.getPanZoomController();
|
||||
mMarginsAnimator = mLayerClient.getLayerMarginsAnimator();
|
||||
|
||||
@ -218,6 +223,16 @@ public class LayerView extends FrameLayout {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchDraw(final Canvas canvas) {
|
||||
super.dispatchDraw(canvas);
|
||||
|
||||
// We must have a layer client to get valid viewport metrics
|
||||
if (mLayerClient != null) {
|
||||
mOverscroll.draw(canvas, getViewportMetrics());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||
@ -487,6 +502,8 @@ public class LayerView extends FrameLayout {
|
||||
if (mListener != null) {
|
||||
mListener.sizeChanged(width, height);
|
||||
}
|
||||
|
||||
mOverscroll.setSize(width, height);
|
||||
}
|
||||
|
||||
private void surfaceChanged(int width, int height) {
|
||||
@ -495,6 +512,8 @@ public class LayerView extends FrameLayout {
|
||||
if (mListener != null) {
|
||||
mListener.surfaceChanged(width, height);
|
||||
}
|
||||
|
||||
mOverscroll.setSize(width, height);
|
||||
}
|
||||
|
||||
private void onDestroyed() {
|
||||
|
@ -104,4 +104,7 @@ class NativePanZoomController implements PanZoomController, GeckoEventListener {
|
||||
}
|
||||
|
||||
public native void updateScrollOffset(float cssX, float cssY);
|
||||
|
||||
public void setOverscrollHandler(final Overscroll listener) {
|
||||
}
|
||||
}
|
||||
|
127
mobile/android/base/gfx/Overscroll.java
Normal file
127
mobile/android/base/gfx/Overscroll.java
Normal file
@ -0,0 +1,127 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.gfx;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.support.v4.widget.EdgeEffectCompat;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.view.View;
|
||||
|
||||
public class Overscroll {
|
||||
// Used to index particular edges in the edges array
|
||||
private static final int TOP = 0;
|
||||
private static final int BOTTOM = 1;
|
||||
private static final int LEFT = 2;
|
||||
private static final int RIGHT = 3;
|
||||
|
||||
// All four edges of the screen
|
||||
private final EdgeEffectCompat[] mEdges = new EdgeEffectCompat[4];
|
||||
|
||||
// The view we're showing this overscroll on.
|
||||
private final View mView;
|
||||
|
||||
// The axis to show overscroll on.
|
||||
public enum Axis {
|
||||
X,
|
||||
Y,
|
||||
};
|
||||
|
||||
public Overscroll(final View v) {
|
||||
mView = v;
|
||||
Context context = v.getContext();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mEdges[i] = new EdgeEffectCompat(context);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSize(final int width, final int height) {
|
||||
mEdges[LEFT].setSize(height, width);
|
||||
mEdges[RIGHT].setSize(height, width);
|
||||
mEdges[TOP].setSize(width, height);
|
||||
mEdges[BOTTOM].setSize(width, height);
|
||||
}
|
||||
|
||||
private EdgeEffectCompat getEdgeForAxisAndSide(final Axis axis, final float side) {
|
||||
if (axis == Axis.Y) {
|
||||
if (side < 0) {
|
||||
return mEdges[TOP];
|
||||
} else {
|
||||
return mEdges[BOTTOM];
|
||||
}
|
||||
} else {
|
||||
if (side < 0) {
|
||||
return mEdges[LEFT];
|
||||
} else {
|
||||
return mEdges[RIGHT];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setVelocity(final float velocity, final Axis axis) {
|
||||
final EdgeEffectCompat edge = getEdgeForAxisAndSide(axis, velocity);
|
||||
|
||||
// If we're showing overscroll already, start fading it out.
|
||||
if (!edge.isFinished()) {
|
||||
edge.onRelease();
|
||||
} else {
|
||||
// Otherwise, show an absorb effect
|
||||
edge.onAbsorb((int)velocity);
|
||||
}
|
||||
|
||||
ViewCompat.postInvalidateOnAnimation(mView);
|
||||
}
|
||||
|
||||
public void setDistance(final float distance, final Axis axis) {
|
||||
// The first overscroll event often has zero distance. Throw it out
|
||||
if (distance == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
final EdgeEffectCompat edge = getEdgeForAxisAndSide(axis, (int)distance);
|
||||
edge.onPull(distance / (axis == Axis.X ? mView.getWidth() : mView.getHeight()));
|
||||
ViewCompat.postInvalidateOnAnimation(mView);
|
||||
}
|
||||
|
||||
public void draw(final Canvas canvas, final ImmutableViewportMetrics metrics) {
|
||||
if (metrics == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're pulling an edge, or fading it out, draw!
|
||||
boolean invalidate = false;
|
||||
if (!mEdges[TOP].isFinished()) {
|
||||
invalidate |= draw(mEdges[TOP], canvas, metrics.marginLeft, metrics.marginTop, 0);
|
||||
}
|
||||
|
||||
if (!mEdges[BOTTOM].isFinished()) {
|
||||
invalidate |= draw(mEdges[BOTTOM], canvas, mView.getWidth(), mView.getHeight(), 180);
|
||||
}
|
||||
|
||||
if (!mEdges[LEFT].isFinished()) {
|
||||
invalidate |= draw(mEdges[LEFT], canvas, metrics.marginLeft, mView.getHeight(), 270);
|
||||
}
|
||||
|
||||
if (!mEdges[RIGHT].isFinished()) {
|
||||
invalidate |= draw(mEdges[RIGHT], canvas, mView.getWidth(), metrics.marginTop, 90);
|
||||
}
|
||||
|
||||
// If the edge effect is animating off screen, invalidate.
|
||||
if (invalidate) {
|
||||
ViewCompat.postInvalidateOnAnimation(mView);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean draw(final EdgeEffectCompat edge, final Canvas canvas, final float translateX, final float translateY, final float rotation) {
|
||||
final int state = canvas.save();
|
||||
canvas.translate(translateX, translateY);
|
||||
canvas.rotate(rotation);
|
||||
boolean invalidate = edge.draw(canvas);
|
||||
canvas.restoreToCount(state);
|
||||
|
||||
return invalidate;
|
||||
}
|
||||
}
|
@ -42,4 +42,6 @@ public interface PanZoomController {
|
||||
public int getOverScrollMode();
|
||||
|
||||
public void updateScrollOffset(float cssX, float cssY);
|
||||
|
||||
public void setOverscrollHandler(final Overscroll controller);
|
||||
}
|
||||
|
@ -65,9 +65,10 @@ public class BrowserHealthRecorder implements GeckoEventListener {
|
||||
private static final String EVENT_ADDONS_CHANGE = "Addons:Change";
|
||||
private static final String EVENT_ADDONS_UNINSTALLING = "Addons:Uninstalling";
|
||||
private static final String EVENT_PREF_CHANGE = "Pref:Change";
|
||||
|
||||
// This is raised from Gecko. It avoids browser.js having to know about the
|
||||
// location that invoked it (the URL bar).
|
||||
|
||||
// This is raised from Gecko and signifies a search via the URL bar (not a bookmarks keyword
|
||||
// search). Using this event (rather than passing the invocation location as an arg) avoids
|
||||
// browser.js having to know about the invocation location.
|
||||
public static final String EVENT_KEYWORD_SEARCH = "Search:Keyword";
|
||||
|
||||
// This is raised from Java. We include the location in the message.
|
||||
@ -681,6 +682,9 @@ public class BrowserHealthRecorder implements GeckoEventListener {
|
||||
|
||||
// Searches.
|
||||
if (EVENT_KEYWORD_SEARCH.equals(event)) {
|
||||
// A search via the URL bar. Since we eliminate all other search possibilities
|
||||
// (e.g. bookmarks keyword, search suggestion) when we initially process the
|
||||
// search URL, this is considered a default search.
|
||||
recordSearch(message.getString("identifier"), "bartext");
|
||||
return;
|
||||
}
|
||||
|
@ -3,17 +3,16 @@
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.mozilla.gecko.home.HomeListView
|
||||
android:id="@+id/list"
|
||||
style="@style/Widget.TopSitesListView"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<org.mozilla.gecko.home.HomeBanner android:id="@+id/home_banner"
|
||||
style="@style/Widget.HomeBanner"
|
||||
@ -26,4 +25,4 @@
|
||||
android:clickable="true"
|
||||
android:focusable="true"/>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
@ -39,7 +39,7 @@
|
||||
[testDistribution]
|
||||
[testFindInPage]
|
||||
[testInputUrlBar]
|
||||
# [testAddSearchEngine] # disabled on fig - bug 880060
|
||||
[testAddSearchEngine]
|
||||
[testImportFromAndroid]
|
||||
[testMasterPassword]
|
||||
[testDeviceSearchEngine]
|
||||
|
@ -4,7 +4,7 @@
|
||||
</header>
|
||||
<body>
|
||||
<form method="get" action="http://www.google.com/search">
|
||||
<input type="text" name="q" size="50" maxlength="255" value="" />
|
||||
<input type="text" name="q" style="width:300px; height:500px;" maxlength="255" value="" />
|
||||
<input type="submit" value="Google Search" />
|
||||
</form>
|
||||
</body>
|
||||
|
@ -5,7 +5,6 @@ import @ANDROID_PACKAGE_NAME@.*;
|
||||
import android.view.View;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.util.Log;
|
||||
import java.util.ArrayList;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@ -13,29 +12,36 @@ import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Test adding a search engine from an input field context menu.
|
||||
* 1. Get the number of existing search engines (As shown in the AwesomeScreen).
|
||||
* 1. Get the number of existing search engines from the SearchEngine:Data event and as displayed in about:home.
|
||||
* 2. Load a page with a text field, open the context menu and add a search engine from the page.
|
||||
* 3. Get the number of search engines after adding the new one and verify it has increased by 1.
|
||||
*/
|
||||
public class testAddSearchEngine extends PixelTest {
|
||||
public class testAddSearchEngine extends AboutHomeTest {
|
||||
private final int MAX_WAIT_TEST_MS = 5000;
|
||||
private final String SEARCH_TEXT = "Firefox for Android";
|
||||
private final String ADD_SEARCHENGINE_OPTION_TEXT = "Add Search Engine";
|
||||
|
||||
@Override
|
||||
protected int getTestType() {
|
||||
return TEST_MOCHITEST;
|
||||
}
|
||||
|
||||
public void testAddSearchEngine() {
|
||||
String blankPageURL = getAbsoluteUrl("/robocop/robocop_blank_01.html");
|
||||
String searchEngineURL = getAbsoluteUrl("/robocop/robocop_search.html");
|
||||
String blankPageURL = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||
String searchEngineURL = getAbsoluteUrl(StringHelper.ROBOCOP_SEARCH_URL);
|
||||
|
||||
blockForGeckoReady();
|
||||
int height = mDriver.getGeckoTop() + 150;
|
||||
int width = mDriver.getGeckoLeft() + 150;
|
||||
|
||||
inputAndLoadUrl(blankPageURL);
|
||||
waitForText("Browser Blank Page 01");
|
||||
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
||||
|
||||
// Get the searchengine data by clicking the awesomebar - this causes Gecko to send Java the list
|
||||
// of search engines.
|
||||
Actions.EventExpecter searchEngineDataEventExpector = mActions.expectGeckoEvent("SearchEngines:Data");
|
||||
focusUrlBar();
|
||||
mActions.sendKeys(SEARCH_TEXT);
|
||||
String eventData = searchEngineDataEventExpector.blockForEventData();
|
||||
searchEngineDataEventExpector.unregisterListener();
|
||||
|
||||
@ -51,38 +57,36 @@ public class testAddSearchEngine extends PixelTest {
|
||||
mAsserter.dumpLog("Search Engines list = " + searchEngines.toString());
|
||||
|
||||
// Verify that the number of displayed search engines is the same as the one received through the SearchEngines:Data event.
|
||||
verifyDisplayedSearchEnginesCount("Browser Blank Page 01", initialNumSearchEngines);
|
||||
verifyDisplayedSearchEnginesCount(initialNumSearchEngines);
|
||||
|
||||
// Load the page for the search engine to add.
|
||||
inputAndLoadUrl(searchEngineURL);
|
||||
waitForText("Robocop Search Engine");
|
||||
waitForText(StringHelper.ROBOCOP_SEARCH_TITLE);
|
||||
verifyPageTitle(StringHelper.ROBOCOP_SEARCH_TITLE);
|
||||
|
||||
// Used to long-tap on the search input box for the search engine to add.
|
||||
int height = mDriver.getGeckoTop() + 10;
|
||||
int width = mDriver.getGeckoLeft() + 20;
|
||||
getInstrumentation().waitForIdleSync();
|
||||
mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height));
|
||||
mSolo.clickLongOnScreen(width,height);
|
||||
if (!waitForText("Add Search Engine")) {
|
||||
// TODO: clickLongOnScreen does not always work - known Robotium issue - . Clicking a second time seems to work.
|
||||
mAsserter.dumpLog("Something went wrong and the context menu was not opened. Trying again");
|
||||
mSolo.clickLongOnScreen(width,height);
|
||||
}
|
||||
mAsserter.ok(waitForText("Add Search Engine"), "Waiting for the context menu to be opened", "The context menu was opened");
|
||||
|
||||
mAsserter.ok(waitForText(ADD_SEARCHENGINE_OPTION_TEXT), "Waiting for the context menu to be opened", "The context menu was opened");
|
||||
|
||||
// Add the search engine
|
||||
mSolo.clickOnText("Add Search Engine");
|
||||
mSolo.clickOnText(ADD_SEARCHENGINE_OPTION_TEXT);
|
||||
waitForText("Cancel");
|
||||
clickOnButton("OK");
|
||||
mAsserter.ok(!mSolo.searchText("Add Search Engine"), "Adding the Search Engine", "The add Search Engine pop-up has been closed");
|
||||
mAsserter.ok(!mSolo.searchText(ADD_SEARCHENGINE_OPTION_TEXT), "Adding the Search Engine", "The add Search Engine pop-up has been closed");
|
||||
waitForText(StringHelper.ROBOCOP_SEARCH_TITLE); // Make sure the pop-up is closed and we are back at the searchengine page
|
||||
|
||||
// Load Robocop Blank 1 again to give the time for the searchengine to be added
|
||||
// TODO: This is a potential source of intermittent oranges - it's a race condition!
|
||||
loadAndPaint(blankPageURL);
|
||||
waitForText("Browser Blank Page 01");
|
||||
loadUrl(blankPageURL);
|
||||
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
||||
|
||||
// Load search engines again and check that the quantity of engines has increased by 1.
|
||||
searchEngineDataEventExpector = mActions.expectGeckoEvent("SearchEngines:Data");
|
||||
focusUrlBar();
|
||||
mActions.sendKeys(SEARCH_TEXT);
|
||||
eventData = searchEngineDataEventExpector.blockForEventData();
|
||||
|
||||
try {
|
||||
@ -97,7 +101,7 @@ public class testAddSearchEngine extends PixelTest {
|
||||
mAsserter.is(searchEngines.size(), initialNumSearchEngines + 1, "Checking the number of Search Engines has increased");
|
||||
|
||||
// Verify that the number of displayed searchengines is the same as the one received through the SearchEngines:Data event.
|
||||
verifyDisplayedSearchEnginesCount("Browser Blank Page 01", initialNumSearchEngines + 1);
|
||||
verifyDisplayedSearchEnginesCount(initialNumSearchEngines + 1);
|
||||
searchEngineDataEventExpector.unregisterListener();
|
||||
}
|
||||
|
||||
@ -123,51 +127,21 @@ public class testAddSearchEngine extends PixelTest {
|
||||
|
||||
/**
|
||||
* Method to verify that the displayed number of search engines matches the expected number.
|
||||
* Uses a BooleanTest which counts how many SearchEngineRow instances are being displayed
|
||||
* in the Awesomescreen.
|
||||
* @param waitText Text from the loaded page to expect. Used to detect when the Awesomescreen
|
||||
* close animation has completed.
|
||||
* @param expectedCountParam The expected number of search engines.
|
||||
* @param expectedCount The expected number of search engines.
|
||||
*/
|
||||
public void verifyDisplayedSearchEnginesCount(String waitText, int expectedCountParam) {
|
||||
final int expectedCount = expectedCountParam;
|
||||
mActions.sendKeys("Firefox for Android");
|
||||
public void verifyDisplayedSearchEnginesCount(final int expectedCount) {
|
||||
mSolo.clearEditText(0);
|
||||
mActions.sendKeys(SEARCH_TEXT);
|
||||
boolean correctNumSearchEnginesDisplayed = waitForTest(new BooleanTest() {
|
||||
@Override
|
||||
public boolean test() {
|
||||
ArrayList<ListView> views;
|
||||
int searchEngineCount = 0;
|
||||
views = mSolo.getCurrentViews(ListView.class);
|
||||
for (ListView view : views) {
|
||||
ListAdapter adapter = view.getAdapter();
|
||||
if (adapter != null) {
|
||||
// Only count SearchEngineRow views - other views are not relavent to this test.
|
||||
try {
|
||||
ClassLoader classLoader = getActivity().getClassLoader();
|
||||
Class searchEngineRow = classLoader.loadClass("org.mozilla.gecko.SearchEngineRow");
|
||||
for (int i = 0; i < adapter.getCount(); i++ ) {
|
||||
View item = view.getChildAt(i);
|
||||
if (searchEngineRow.isInstance(item)) {
|
||||
searchEngineCount++;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
mAsserter.dumpLog("Exception in verifyDisplayedSearchEnginesCount", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (searchEngineCount == expectedCount) {
|
||||
return true;
|
||||
} else {
|
||||
mAsserter.dumpLog("The wrong number of search engines was found. Found " + searchEngineCount + " search engines");
|
||||
return false;
|
||||
}
|
||||
return (findListViewWithTag("browser_search").getAdapter().getCount() == expectedCount);
|
||||
}
|
||||
}, MAX_WAIT_TEST_MS);
|
||||
|
||||
// Close the Awesomescreen
|
||||
// Exit about:home
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
||||
waitForText(waitText);
|
||||
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
||||
mAsserter.ok(correctNumSearchEnginesDisplayed, expectedCount + " Search Engines should be displayed" , "The correct number of Search Engines has been displayed");
|
||||
}
|
||||
}
|
||||
|
@ -62,17 +62,9 @@ public class FaviconView extends ImageView {
|
||||
* in this view with the coloured background.
|
||||
*/
|
||||
private void formatImage() {
|
||||
// If we're called before bitmap is set, just show the default.
|
||||
if (mIconBitmap == null) {
|
||||
setImageResource(R.drawable.favicon);
|
||||
hideBackground();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're called before size set, abort.
|
||||
if (mActualWidth == 0 || mActualHeight == 0) {
|
||||
hideBackground();
|
||||
setImageResource(R.drawable.favicon);
|
||||
// If we're called before bitmap is set, or before size is set, show blank.
|
||||
if (mIconBitmap == null || mActualWidth == 0 || mActualHeight == 0) {
|
||||
clearImage();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -142,6 +134,11 @@ public class FaviconView extends ImageView {
|
||||
* (Favicons class), so as to exploit caching.
|
||||
*/
|
||||
private void updateImageInternal(Bitmap bitmap, String key, boolean allowScaling) {
|
||||
if (bitmap == null) {
|
||||
showDefaultFavicon();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reassigning the same bitmap? Don't bother.
|
||||
if (mUnscaledBitmap == bitmap) {
|
||||
return;
|
||||
@ -155,12 +152,21 @@ public class FaviconView extends ImageView {
|
||||
formatImage();
|
||||
}
|
||||
|
||||
private void showDefaultFavicon() {
|
||||
setImageResource(R.drawable.favicon);
|
||||
hideBackground();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear image and background shown by this view.
|
||||
*/
|
||||
public void clearImage() {
|
||||
setImageResource(0);
|
||||
hideBackground();
|
||||
mUnscaledBitmap = null;
|
||||
mIconBitmap = null;
|
||||
mIconKey = null;
|
||||
mScalingExpected = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1402,7 +1402,9 @@ var BrowserApp = {
|
||||
break;
|
||||
|
||||
case "keyword-search":
|
||||
// This assumes that the user can only perform a keyword search on the selected tab.
|
||||
// This event refers to a search via the URL bar, not a bookmarks
|
||||
// keyword search. Note that this code assumes that the user can only
|
||||
// perform a keyword search on the selected tab.
|
||||
this.selectedTab.userSearch = aData;
|
||||
|
||||
let engine = aSubject.QueryInterface(Ci.nsISearchEngine);
|
||||
|
@ -13,6 +13,11 @@ const URI_GENERIC_ICON_DOWNLOAD = "drawable://alert_download";
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||
"resource://gre/modules/Downloads.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// HelperApp Launcher Dialog
|
||||
// -----------------------------------------------------------------------
|
||||
@ -30,15 +35,16 @@ HelperAppLauncherDialog.prototype = {
|
||||
},
|
||||
|
||||
promptForSaveToFile: function hald_promptForSaveToFile(aLauncher, aContext, aDefaultFile, aSuggestedFileExt, aForcePrompt) {
|
||||
// Retrieve the user's default download directory
|
||||
let dnldMgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
|
||||
let defaultFolder = dnldMgr.userDownloadsDirectory;
|
||||
return Task.spawn(function() {
|
||||
// Retrieve the user's default download directory
|
||||
let defaultFolder = yield Downloads.getPreferredDownloadsDirectory();
|
||||
|
||||
try {
|
||||
file = this.validateLeafName(defaultFolder, aDefaultFile, aSuggestedFileExt);
|
||||
} catch (e) { }
|
||||
try {
|
||||
file = this.validateLeafName(defaultFolder, aDefaultFile, aSuggestedFileExt);
|
||||
} catch (e) { }
|
||||
|
||||
return file;
|
||||
throw new Task.Result(file);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
validateLeafName: function hald_validateLeafName(aLocalFile, aLeafName, aFileExt) {
|
||||
|
@ -182,7 +182,7 @@ NSSDialogs.prototype = {
|
||||
this.getString("nssdialogs.cancel.label")
|
||||
])
|
||||
.addLabel({ id: "requestedDetails", label: serverRequestedDetails } )
|
||||
.addMenuList({
|
||||
.addMenulist({
|
||||
id: "nicknames",
|
||||
label: this.getString("clientAuthAsk.message2"),
|
||||
values: certNickList, selected: selectedIndex
|
||||
|
@ -704,7 +704,9 @@ Connection::databaseElementExists(enum DatabaseElementType aElementType,
|
||||
{
|
||||
if (!mDBConn) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
nsAutoCString query("SELECT name FROM sqlite_master WHERE type = '");
|
||||
nsCString query("SELECT name FROM (SELECT * FROM sqlite_master UNION ALL "
|
||||
"SELECT * FROM sqlite_temp_master) "
|
||||
"WHERE type = '");
|
||||
switch (aElementType) {
|
||||
case INDEX:
|
||||
query.Append("index");
|
||||
|
@ -108,6 +108,19 @@ add_task(function test_indexExists_not_created()
|
||||
do_check_false(msc.indexExists("foo"));
|
||||
});
|
||||
|
||||
add_task(function test_temp_tableExists_and_indexExists()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.executeSimpleSQL("CREATE TEMP TABLE test_temp(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)");
|
||||
do_check_true(msc.tableExists("test_temp"));
|
||||
|
||||
msc.executeSimpleSQL("CREATE INDEX test_temp_ind ON test_temp (name)");
|
||||
do_check_true(msc.indexExists("test_temp_ind"));
|
||||
|
||||
msc.executeSimpleSQL("DROP INDEX test_temp_ind");
|
||||
msc.executeSimpleSQL("DROP TABLE test_temp");
|
||||
});
|
||||
|
||||
add_task(function test_createTable_not_created()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
|
@ -464,15 +464,26 @@ class MochiRemote(Mochitest):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def printScreenshot(self):
|
||||
try:
|
||||
image = self._dm.pullFile("/mnt/sdcard/Robotium-Screenshots/robocop-screenshot.jpg")
|
||||
encoded = base64.b64encode(image)
|
||||
log.info("SCREENSHOT: data:image/jpg;base64,%s", encoded)
|
||||
except:
|
||||
# If the test passes, no screenshot will be generated and
|
||||
# pullFile will fail -- continue silently.
|
||||
pass
|
||||
def printScreenshots(self, screenShotDir):
|
||||
# TODO: This can be re-written after completion of bug 749421
|
||||
if not self._dm.dirExists(screenShotDir):
|
||||
log.info("SCREENSHOT: No ScreenShots directory available: " + screenShotDir)
|
||||
return
|
||||
|
||||
printed = 0
|
||||
for name in self._dm.listFiles(screenShotDir):
|
||||
fullName = screenShotDir + "/" + name
|
||||
log.info("SCREENSHOT: FOUND: [%s]", fullName)
|
||||
try:
|
||||
image = self._dm.pullFile(fullName)
|
||||
encoded = base64.b64encode(image)
|
||||
log.info("SCREENSHOT: data:image/jpg;base64,%s", encoded)
|
||||
printed += 1
|
||||
except:
|
||||
log.info("SCREENSHOT: Could not be parsed")
|
||||
pass
|
||||
|
||||
log.info("SCREENSHOT: TOTAL PRINTED: [%s]", printed)
|
||||
|
||||
def printDeviceInfo(self, printLogcat=False):
|
||||
try:
|
||||
@ -654,7 +665,8 @@ def main():
|
||||
if (options.dm_trans == "sut"):
|
||||
dm._runCmds([{"cmd": " ".join(cmd)}])
|
||||
try:
|
||||
dm.removeDir("/mnt/sdcard/Robotium-Screenshots")
|
||||
screenShotDir = "/mnt/sdcard/Robotium-Screenshots"
|
||||
dm.removeDir(screenShotDir)
|
||||
dm.recordLogcat()
|
||||
result = mochitest.runTests(options)
|
||||
if result != 0:
|
||||
@ -662,7 +674,7 @@ def main():
|
||||
log_result = mochitest.addLogData()
|
||||
if result != 0 or log_result != 0:
|
||||
mochitest.printDeviceInfo(printLogcat=True)
|
||||
mochitest.printScreenshot()
|
||||
mochitest.printScreenshots(screenShotDir)
|
||||
# Ensure earlier failures aren't overwritten by success on this run
|
||||
if retVal is None or retVal == 0:
|
||||
retVal = result
|
||||
|
@ -715,8 +715,15 @@ var StyleRuleActor = protocol.ActorClass({
|
||||
|
||||
// Use a fresh element for each call to this function to prevent side effects
|
||||
// that pop up based on property values that were already set on the element.
|
||||
let tempElement = Services.appShell.hiddenDOMWindow.
|
||||
document.createElement("div");
|
||||
|
||||
let document;
|
||||
if (this.rawNode) {
|
||||
document = this.rawNode.ownerDocument;
|
||||
} else {
|
||||
document = this.rawRule.parentStyleSheet.ownerNode.ownerDocument;
|
||||
}
|
||||
|
||||
let tempElement = document.createElement("div");
|
||||
|
||||
for (let mod of modifications) {
|
||||
if (mod.type === "set") {
|
||||
|
@ -600,9 +600,7 @@ OpenedConnection.prototype = Object.freeze({
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether a table exists in the database.
|
||||
*
|
||||
* IMPROVEMENT: Look for temporary tables.
|
||||
* Whether a table exists in the database (both persistent and temporary tables).
|
||||
*
|
||||
* @param name
|
||||
* (string) Name of the table.
|
||||
@ -611,7 +609,9 @@ OpenedConnection.prototype = Object.freeze({
|
||||
*/
|
||||
tableExists: function (name) {
|
||||
return this.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name=?",
|
||||
"SELECT name FROM (SELECT * FROM sqlite_master UNION ALL " +
|
||||
"SELECT * FROM sqlite_temp_master) " +
|
||||
"WHERE type = 'table' AND name=?",
|
||||
[name])
|
||||
.then(function onResult(rows) {
|
||||
return Promise.resolve(rows.length > 0);
|
||||
@ -620,9 +620,7 @@ OpenedConnection.prototype = Object.freeze({
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether a named index exists.
|
||||
*
|
||||
* IMPROVEMENT: Look for indexes in temporary tables.
|
||||
* Whether a named index exists (both persistent and temporary tables).
|
||||
*
|
||||
* @param name
|
||||
* (string) Name of the index.
|
||||
@ -631,7 +629,9 @@ OpenedConnection.prototype = Object.freeze({
|
||||
*/
|
||||
indexExists: function (name) {
|
||||
return this.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type='index' AND name=?",
|
||||
"SELECT name FROM (SELECT * FROM sqlite_master UNION ALL " +
|
||||
"SELECT * FROM sqlite_temp_master) " +
|
||||
"WHERE type = 'index' AND name=?",
|
||||
[name])
|
||||
.then(function onResult(rows) {
|
||||
return Promise.resolve(rows.length > 0);
|
||||
|
@ -60,6 +60,22 @@ function getDummyDatabase(name, extraOptions={}) {
|
||||
throw new Task.Result(c);
|
||||
}
|
||||
|
||||
function getDummyTempDatabase(name, extraOptions={}) {
|
||||
const TABLES = {
|
||||
dirs: "id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT",
|
||||
files: "id INTEGER PRIMARY KEY AUTOINCREMENT, dir_id INTEGER, path TEXT",
|
||||
};
|
||||
|
||||
let c = yield getConnection(name, extraOptions);
|
||||
c._initialStatementCount = 0;
|
||||
|
||||
for (let [k, v] in Iterator(TABLES)) {
|
||||
yield c.execute("CREATE TEMP TABLE " + k + "(" + v + ")");
|
||||
c._initialStatementCount++;
|
||||
}
|
||||
|
||||
throw new Task.Result(c);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
Cu.import("resource://testing-common/services-common/logging.js");
|
||||
@ -203,6 +219,27 @@ add_task(function test_index_exists() {
|
||||
yield c.close();
|
||||
});
|
||||
|
||||
add_task(function test_temp_table_exists() {
|
||||
let c = yield getDummyTempDatabase("temp_table_exists");
|
||||
|
||||
do_check_false(yield c.tableExists("temp_does_not_exist"));
|
||||
do_check_true(yield c.tableExists("dirs"));
|
||||
do_check_true(yield c.tableExists("files"));
|
||||
|
||||
yield c.close();
|
||||
});
|
||||
|
||||
add_task(function test_temp_index_exists() {
|
||||
let c = yield getDummyTempDatabase("temp_index_exists");
|
||||
|
||||
do_check_false(yield c.indexExists("temp_does_not_exist"));
|
||||
|
||||
yield c.execute("CREATE INDEX my_index ON dirs (path)");
|
||||
do_check_true(yield c.indexExists("my_index"));
|
||||
|
||||
yield c.close();
|
||||
});
|
||||
|
||||
add_task(function test_close_cached() {
|
||||
let c = yield getDummyDatabase("close_cached");
|
||||
|
||||
|
@ -26,6 +26,7 @@ const PREF_EM_CERT_CHECKATTRIBUTES = "extensions.hotfix.cert.checkAttributes"
|
||||
const PREF_EM_HOTFIX_CERTS = "extensions.hotfix.certs.";
|
||||
const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
|
||||
const PREF_SELECTED_LOCALE = "general.useragent.locale";
|
||||
const UNKNOWN_XPCOM_ABI = "unknownABI";
|
||||
|
||||
const UPDATE_REQUEST_VERSION = 2;
|
||||
const CATEGORY_UPDATE_PARAMS = "extension-update-params";
|
||||
|
Loading…
x
Reference in New Issue
Block a user