--HG--
extra : commitid : KfjY9JJOq3w
This commit is contained in:
Wes Kocher 2016-01-21 17:36:22 -08:00
Родитель 25c1f56cee 1809816b44
Коммит 2ed2b43c29
275 изменённых файлов: 3958 добавлений и 16485 удалений

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

@ -4,9 +4,6 @@
# Exclude expected objdirs.
obj*/**
# Temporarily ignore HTML files that still need to be fixed.
devtools/**/*.html
# We ignore all these directories by default, until we get them enabled.
# If you are enabling a directory, please add directory specific exclusions
# below.
@ -17,7 +14,6 @@ caps/**
chrome/**
config/**
db/**
devtools/**
docshell/**
dom/**
editor/**
@ -91,24 +87,52 @@ browser/locales/**
browser/extensions/loop/**
# devtools/ exclusions
# Ignore d3
devtools/client/shared/d3.js
devtools/client/webaudioeditor/lib/dagre-d3.js
devtools/*.js
devtools/client/*.js
devtools/client/aboutdebugging/**
devtools/client/animationinspector/**
devtools/client/canvasdebugger/**
devtools/client/commandline/**
devtools/client/debugger/**
devtools/client/eyedropper/**
devtools/client/framework/**
# devtools/client/inspector/shared/*.js files are eslint-clean, so they aren't
# included in the ignore list.
devtools/client/inspector/computed/**
devtools/client/inspector/fonts/**
devtools/client/inspector/layout/**
devtools/client/inspector/markup/**
devtools/client/inspector/rules/**
devtools/client/inspector/shared/test/**
devtools/client/inspector/test/**
devtools/client/inspector/*.js
devtools/client/jsonview/**
devtools/client/memory/**
devtools/client/netmonitor/**
devtools/client/performance/**
devtools/client/projecteditor/**
devtools/client/promisedebugger/**
devtools/client/responsivedesign/**
devtools/client/scratchpad/**
devtools/client/shadereditor/**
devtools/client/shared/**
devtools/client/sourceeditor/**
devtools/client/storage/**
devtools/client/styleeditor/**
devtools/client/tilt/**
devtools/client/webaudioeditor/**
devtools/client/webconsole/**
devtools/client/webide/**
devtools/server/**
devtools/shared/**
# Ignore codemirror
devtools/client/sourceeditor/codemirror/*.js
devtools/client/sourceeditor/codemirror/**/*.js
devtools/client/sourceeditor/test/codemirror/*
# Ignore jquery test libs
devtools/client/markupview/test/lib_*
# Ignore pre-processed files
# Ignore devtools pre-processed files
devtools/client/framework/toolbox-process-window.js
devtools/client/performance/system.js
devtools/client/webide/webide-prefs.js
devtools/client/preferences/**
# Ignore various libs
# Ignore devtools third-party libs
devtools/shared/jsbeautify/*
devtools/shared/acorn/*
devtools/client/sourceeditor/tern/*
@ -117,6 +141,12 @@ devtools/shared/sourcemap/*
devtools/shared/qrcode/decoder/*
devtools/shared/qrcode/encoder/*
devtools/client/shared/vendor/*
devtools/client/shared/d3.js
devtools/client/webaudioeditor/lib/dagre-d3.js
devtools/client/sourceeditor/codemirror/*.js
devtools/client/sourceeditor/codemirror/**/*.js
devtools/client/sourceeditor/test/codemirror/*
devtools/client/markupview/test/lib_*
# mobile/android/ exclusions
mobile/android/chrome/content

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

@ -6,6 +6,7 @@
"rules": {
"mozilla/components-imports": 1,
"mozilla/import-globals-from": 1,
"mozilla/this-top-level-scope": 1,
},
"env": {
"es6": true

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee",
"git_revision": "89602d6ae53ecf4129b35a84e49d25b9fd37bc39",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "d74e738cd626558fb9dc289500ad28ae29deab03",
"revision": "ea9b9cc69315e86bf7198ec0d57a267e64345b32",
"repo_path": "integration/gaia-central"
}

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="619766a1ce78d50fb8a3b5a9e0821c335a0ed7ee"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="89602d6ae53ecf4129b35a84e49d25b9fd37bc39"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -2275,16 +2275,22 @@ function BrowserViewSource(browser) {
});
}
// doc - document to use for source, or null for this window's document
// documentURL - URL of the document to view, or null for this window's document
// initialTab - name of the initial tab to display, or null for the first tab
// imageElement - image to load in the Media Tab of the Page Info window; can be null/omitted
// frameOuterWindowID - the id of the frame that the context menu opened in; can be null/omitted
function BrowserPageInfo(doc, initialTab, imageElement, frameOuterWindowID) {
var args = {doc: doc, initialTab: initialTab, imageElement: imageElement,
frameOuterWindowID: frameOuterWindowID};
function BrowserPageInfo(documentURL, initialTab, imageElement, frameOuterWindowID) {
if (documentURL instanceof HTMLDocument) {
Deprecated.warning("Please pass the location URL instead of the document " +
"to BrowserPageInfo() as the first argument.",
"https://bugzilla.mozilla.org/show_bug.cgi?id=1238180");
documentURL = documentURL.location;
}
let args = { initialTab, imageElement, frameOuterWindowID };
var windows = Services.wm.getEnumerator("Browser:page-info");
var documentURL = doc ? doc.location : window.gBrowser.selectedBrowser.currentURI.spec;
documentURL = documentURL || window.gBrowser.selectedBrowser.currentURI.spec;
// Check for windows matching the url
while (windows.hasMoreElements()) {

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

@ -1065,12 +1065,11 @@ nsContextMenu.prototype = {
},
viewInfo: function() {
BrowserPageInfo(this.target.ownerDocument.defaultView.top.document);
BrowserPageInfo();
},
viewImageInfo: function() {
BrowserPageInfo(this.target.ownerDocument.defaultView.top.document,
"mediaTab", this.target);
BrowserPageInfo(null, "mediaTab", this.target);
},
viewImageDesc: function(e) {
@ -1082,7 +1081,7 @@ nsContextMenu.prototype = {
},
viewFrameInfo: function() {
BrowserPageInfo(this.target.ownerDocument, null, null,
BrowserPageInfo(gContextMenuContentData.docLocation, null, null,
this.frameOuterWindowID);
},

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

@ -9,7 +9,8 @@ function test() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
var doc = gBrowser.contentDocument;
var pageInfo = BrowserPageInfo(doc, "mediaTab");
var pageInfo = BrowserPageInfo(gBrowser.selectedBrowser.currentURI.spec,
"mediaTab");
pageInfo.addEventListener("load", function () {
pageInfo.removeEventListener("load", arguments.callee, true);

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

@ -10,7 +10,8 @@ function test() {
var doc = gBrowser.contentDocument;
var testImg = doc.getElementById("test-image");
var pageInfo = BrowserPageInfo(doc, "mediaTab", testImg);
var pageInfo = BrowserPageInfo(gBrowser.selectedBrowser.currentURI.spec,
"mediaTab", testImg);
pageInfo.addEventListener("load", function () {
pageInfo.removeEventListener("load", arguments.callee, true);

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

@ -2,179 +2,87 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* testTabSwitchContext() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"page_action": {
"default_icon": "default.png",
"default_popup": "default.html",
"default_title": "Default Title \u263a",
},
"permissions": ["tabs"],
},
function* runTests(options) {
function background(getTests) {
let tabs;
let tests;
background: function() {
let details = [
{ "icon": browser.runtime.getURL("default.png"),
"popup": browser.runtime.getURL("default.html"),
"title": "Default Title \u263a" },
{ "icon": browser.runtime.getURL("1.png"),
"popup": browser.runtime.getURL("default.html"),
"title": "Default Title \u263a" },
{ "icon": browser.runtime.getURL("2.png"),
"popup": browser.runtime.getURL("2.html"),
"title": "Title 2" },
];
let tabs;
let tests;
let allTests = [
expect => {
browser.test.log("Initial state. No icon visible.");
expect(null);
},
expect => {
browser.test.log("Show the icon on the first tab, expect default properties.");
browser.pageAction.show(tabs[0]);
expect(details[0]);
},
expect => {
browser.test.log("Change the icon. Expect default properties excluding the icon.");
browser.pageAction.setIcon({ tabId: tabs[0], path: "1.png" });
expect(details[1]);
},
expect => {
browser.test.log("Create a new tab. No icon visible.");
browser.tabs.create({ active: true, url: "about:blank?0" }, tab => {
tabs.push(tab.id);
expect(null);
});
},
expect => {
browser.test.log("Change properties. Expect new properties.");
let tabId = tabs[1];
browser.pageAction.show(tabId);
browser.pageAction.setIcon({ tabId, path: "2.png" });
browser.pageAction.setPopup({ tabId, popup: "2.html" });
browser.pageAction.setTitle({ tabId, title: "Title 2" });
expect(details[2]);
},
expect => {
browser.test.log("Navigate to a new page. Expect icon hidden.");
// TODO: This listener should not be necessary, but the |tabs.update|
// callback currently fires too early in e10s windows.
browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
if (tabId == tabs[1] && changed.url) {
browser.tabs.onUpdated.removeListener(listener);
expect(null);
}
});
browser.tabs.update(tabs[1], { url: "about:blank?1" });
},
expect => {
browser.test.log("Show the icon. Expect default properties again.");
browser.pageAction.show(tabs[1]);
expect(details[0]);
},
expect => {
browser.test.log("Switch back to the first tab. Expect previously set properties.");
browser.tabs.update(tabs[0], { active: true }, () => {
expect(details[1]);
});
},
expect => {
browser.test.log("Hide the icon on tab 2. Switch back, expect hidden.");
browser.pageAction.hide(tabs[1]);
browser.tabs.update(tabs[1], { active: true }, () => {
expect(null);
});
},
expect => {
browser.test.log("Switch back to tab 1. Expect previous results again.");
browser.tabs.remove(tabs[1], () => {
expect(details[1]);
});
},
expect => {
browser.test.log("Hide the icon. Expect hidden.");
browser.pageAction.hide(tabs[0]);
expect(null);
},
];
// Gets the current details of the page action, and returns a
// promise that resolves to an object containing them.
function getDetails() {
return new Promise(resolve => {
return browser.tabs.query({ active: true, currentWindow: true }, resolve);
}).then(tabs => {
let tabId = tabs[0].id;
return Promise.all([
new Promise(resolve => browser.pageAction.getTitle({tabId}, resolve)),
new Promise(resolve => browser.pageAction.getPopup({tabId}, resolve))]);
}).then(details => {
return Promise.resolve({ title: details[0],
popup: details[1] });
});
}
// Gets the current details of the page action, and returns a
// promise that resolves to an object containing them.
function getDetails() {
return new Promise(resolve => {
return browser.tabs.query({ active: true, currentWindow: true }, resolve);
}).then(([tab]) => {
let tabId = tab.id;
browser.test.log(`Get details: tab={id: ${tabId}, url: ${JSON.stringify(tab.url)}}`);
return Promise.all([
new Promise(resolve => browser.pageAction.getTitle({tabId}, resolve)),
new Promise(resolve => browser.pageAction.getPopup({tabId}, resolve))]);
}).then(details => {
return Promise.resolve({ title: details[0],
popup: details[1] });
});
}
// Runs the next test in the `tests` array, checks the results,
// and passes control back to the outer test scope.
function nextTest() {
let test = tests.shift();
// Runs the next test in the `tests` array, checks the results,
// and passes control back to the outer test scope.
function nextTest() {
let test = tests.shift();
test(expecting => {
function finish() {
// Check that the actual icon has the expected values, then
// run the next test.
browser.test.sendMessage("nextTest", expecting, tests.length);
}
test(expecting => {
function finish() {
// Check that the actual icon has the expected values, then
// run the next test.
browser.test.sendMessage("nextTest", expecting, tests.length);
}
if (expecting) {
// Check that the API returns the expected values, and then
// run the next test.
getDetails().then(details => {
browser.test.assertEq(expecting.title, details.title,
"expected value from getTitle");
if (expecting) {
// Check that the API returns the expected values, and then
// run the next test.
getDetails().then(details => {
browser.test.assertEq(expecting.title, details.title,
"expected value from getTitle");
browser.test.assertEq(expecting.popup, details.popup,
"expected value from getPopup");
browser.test.assertEq(expecting.popup, details.popup,
"expected value from getPopup");
finish();
});
} else {
finish();
}
});
}
function runTests() {
tabs = [];
tests = allTests.slice();
browser.tabs.query({ active: true, currentWindow: true }, resultTabs => {
tabs[0] = resultTabs[0].id;
nextTest();
});
}
browser.test.onMessage.addListener((msg) => {
if (msg == "runTests") {
runTests();
} else if (msg == "runNextTest") {
nextTest();
});
} else {
browser.test.fail(`Unexpected message: ${msg}`);
finish();
}
});
}
runTests();
},
function runTests() {
tabs = [];
tests = getTests(tabs);
browser.tabs.query({ active: true, currentWindow: true }, resultTabs => {
tabs[0] = resultTabs[0].id;
nextTest();
});
}
browser.test.onMessage.addListener((msg) => {
if (msg == "runTests") {
runTests();
} else if (msg == "runNextTest") {
nextTest();
} else {
browser.test.fail(`Unexpected message: ${msg}`);
}
});
runTests();
}
let extension = ExtensionTestUtils.loadExtension({
manifest: options.manifest,
background: `(${background})(${options.getTests})`,
});
let pageActionId = makeWidgetId(extension.id) + "-page-action";
@ -189,8 +97,10 @@ add_task(function* testTabSwitchContext() {
ok(image, "image exists");
is(image.src, details.icon, "icon URL is correct");
is(image.getAttribute("tooltiptext"), details.title, "image title is correct");
is(image.getAttribute("aria-label"), details.title, "image aria-label is correct");
let title = details.title || options.manifest.name;
is(image.getAttribute("tooltiptext"), title, "image title is correct");
is(image.getAttribute("aria-label"), title, "image aria-label is correct");
// TODO: Popup URL.
}
}
@ -235,4 +145,183 @@ add_task(function* testTabSwitchContext() {
yield BrowserTestUtils.closeWindow(win);
}
}
add_task(function* testTabSwitchContext() {
yield runTests({
manifest: {
"name": "Foo Extension",
"page_action": {
"default_icon": "default.png",
"default_popup": "default.html",
"default_title": "Default Title \u263a",
},
"permissions": ["tabs"],
},
getTests(tabs) {
let details = [
{ "icon": browser.runtime.getURL("default.png"),
"popup": browser.runtime.getURL("default.html"),
"title": "Default Title \u263a" },
{ "icon": browser.runtime.getURL("1.png"),
"popup": browser.runtime.getURL("default.html"),
"title": "Default Title \u263a" },
{ "icon": browser.runtime.getURL("2.png"),
"popup": browser.runtime.getURL("2.html"),
"title": "Title 2" },
{ "icon": browser.runtime.getURL("2.png"),
"popup": browser.runtime.getURL("2.html"),
"title": "Default Title \u263a" },
];
let promiseTabLoad = details => {
return new Promise(resolve => {
browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
if (tabId == details.id && changed.url == details.url) {
browser.tabs.onUpdated.removeListener(listener);
resolve();
}
});
});
};
let tabLoadPromise;
return [
expect => {
browser.test.log("Initial state. No icon visible.");
expect(null);
},
expect => {
browser.test.log("Show the icon on the first tab, expect default properties.");
browser.pageAction.show(tabs[0]);
expect(details[0]);
},
expect => {
browser.test.log("Change the icon. Expect default properties excluding the icon.");
browser.pageAction.setIcon({ tabId: tabs[0], path: "1.png" });
expect(details[1]);
},
expect => {
browser.test.log("Create a new tab. No icon visible.");
browser.tabs.create({ active: true, url: "about:blank?0" }, tab => {
tabLoadPromise = promiseTabLoad({ url: "about:blank?0", id: tab.id });
tabs.push(tab.id);
expect(null);
});
},
expect => {
browser.test.log("Await tab load. No icon visible.");
tabLoadPromise.then(() => {
expect(null);
});
},
expect => {
browser.test.log("Change properties. Expect new properties.");
let tabId = tabs[1];
browser.pageAction.show(tabId);
browser.pageAction.setIcon({ tabId, path: "2.png" });
browser.pageAction.setPopup({ tabId, popup: "2.html" });
browser.pageAction.setTitle({ tabId, title: "Title 2" });
expect(details[2]);
},
expect => {
browser.test.log("Clear the title. Expect default title.");
browser.pageAction.setTitle({ tabId: tabs[1], title: "" });
expect(details[3]);
},
expect => {
browser.test.log("Navigate to a new page. Expect icon hidden.");
// TODO: This listener should not be necessary, but the |tabs.update|
// callback currently fires too early in e10s windows.
promiseTabLoad({ id: tabs[1], url: "about:blank?1" }).then(() => {
expect(null);
});
browser.tabs.update(tabs[1], { url: "about:blank?1" });
},
expect => {
browser.test.log("Show the icon. Expect default properties again.");
browser.pageAction.show(tabs[1]);
expect(details[0]);
},
expect => {
browser.test.log("Switch back to the first tab. Expect previously set properties.");
browser.tabs.update(tabs[0], { active: true }, () => {
expect(details[1]);
});
},
expect => {
browser.test.log("Hide the icon on tab 2. Switch back, expect hidden.");
browser.pageAction.hide(tabs[1]);
browser.tabs.update(tabs[1], { active: true }, () => {
expect(null);
});
},
expect => {
browser.test.log("Switch back to tab 1. Expect previous results again.");
browser.tabs.remove(tabs[1], () => {
expect(details[1]);
});
},
expect => {
browser.test.log("Hide the icon. Expect hidden.");
browser.pageAction.hide(tabs[0]);
expect(null);
},
];
},
});
});
add_task(function* testDefaultTitle() {
yield runTests({
manifest: {
"name": "Foo Extension",
"page_action": {
"default_icon": "icon.png",
},
"permissions": ["tabs"],
},
getTests(tabs) {
let details = [
{ "title": "Foo Extension",
"popup": "",
"icon": browser.runtime.getURL("icon.png") },
{ "title": "Foo Title",
"popup": "",
"icon": browser.runtime.getURL("icon.png") },
];
return [
expect => {
browser.test.log("Initial state. No icon visible.");
expect(null);
},
expect => {
browser.test.log("Show the icon on the first tab, expect extension title as default title.");
browser.pageAction.show(tabs[0]);
expect(details[0]);
},
expect => {
browser.test.log("Change the title. Expect new title.");
browser.pageAction.setTitle({ tabId: tabs[0], title: "Foo Title" });
expect(details[1]);
},
expect => {
browser.test.log("Clear the title. Expect extension title.");
browser.pageAction.setTitle({ tabId: tabs[0], title: "" });
expect(details[0]);
},
];
},
});
});

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

@ -38,6 +38,15 @@ this.TestRunner = {
_libDir: null,
init(extensionPath) {
this._extensionPath = extensionPath;
},
/**
* Load specified sets, execute all combinations of them, and capture screenshots.
*/
start(setNames = null) {
setNames = setNames || defaultSetNames;
let subDirs = ["mozscreenshots",
(new Date()).toISOString().replace(/:/g, "-") + "_" + Services.appinfo.OS];
let screenshotPath = FileUtils.getFile("TmpD", subDirs).path;
@ -48,27 +57,14 @@ this.TestRunner = {
}
log.info("Saving screenshots to:", screenshotPath);
log.debug("TestRunner.init");
let screenshotPrefix = Services.appinfo.appBuildID + "_";
Screenshot.init(screenshotPath, extensionPath, screenshotPrefix);
this._libDir = extensionPath.QueryInterface(Ci.nsIFileURL).file.clone();
Screenshot.init(screenshotPath, this._extensionPath, screenshotPrefix);
this._libDir = this._extensionPath.QueryInterface(Ci.nsIFileURL).file.clone();
this._libDir.append("chrome");
this._libDir.append("mozscreenshots");
this._libDir.append("lib");
// Setup some prefs
Services.prefs.setCharPref("browser.aboutHomeSnippets.updateUrl", "data:");
Services.prefs.setCharPref("extensions.ui.lastCategory", "addons://list/extension");
// Don't let the caret blink since it causes false positives for image diffs
Services.prefs.setIntPref("ui.caretBlinkTime", -1);
},
/**
* Load specified sets, execute all combinations of them, and capture screenshots.
*/
start(setNames = null) {
setNames = setNames || defaultSetNames;
let sets = this.loadSets(setNames);
log.info(sets.length + " sets:", setNames);
@ -78,6 +74,12 @@ this.TestRunner = {
this.currentComboIndex = this.completedCombos = 0;
this._lastCombo = null;
// Setup some prefs
Services.prefs.setCharPref("browser.aboutHomeSnippets.updateUrl", "data:");
Services.prefs.setCharPref("extensions.ui.lastCategory", "addons://list/extension");
// Don't let the caret blink since it causes false positives for image diffs
Services.prefs.setIntPref("ui.caretBlinkTime", -1);
return Task.spawn(function* doStart() {
for (let i = 0; i < this.combos.length;
i++){

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

@ -3805,7 +3805,6 @@ MOZ_ANDROID_HISTORY=
MOZ_WEBSMS_BACKEND=
MOZ_ANDROID_BEAM=
MOZ_LOCALE_SWITCHER=
MOZ_ANDROID_READING_LIST_SERVICE=
MOZ_ANDROID_SEARCH_ACTIVITY=
MOZ_ANDROID_DOWNLOADS_INTEGRATION=
MOZ_ANDROID_GCM=
@ -4883,13 +4882,6 @@ if test -n "$MOZ_ANDROID_SEARCH_ACTIVITY"; then
AC_DEFINE(MOZ_ANDROID_SEARCH_ACTIVITY)
fi
dnl ========================================================
dnl = Include Reading List service on Android
dnl ========================================================
if test -n "$MOZ_ANDROID_READING_LIST_SERVICE"; then
AC_DEFINE(MOZ_ANDROID_READING_LIST_SERVICE)
fi
dnl ========================================================
dnl = Include Mozilla Location Service Stumbler on Android
dnl ========================================================
@ -8555,7 +8547,6 @@ AC_SUBST(MOZ_LOCALE_SWITCHER)
AC_SUBST(MOZ_DISABLE_GECKOVIEW)
AC_SUBST(MOZ_ANDROID_GCM)
AC_SUBST(MOZ_ANDROID_GECKOLIBS_AAR)
AC_SUBST(MOZ_ANDROID_READING_LIST_SERVICE)
AC_SUBST(MOZ_ANDROID_SEARCH_ACTIVITY)
AC_SUBST(MOZ_ANDROID_MLS_STUMBLER)
AC_SUBST(MOZ_ANDROID_DOWNLOADS_INTEGRATION)

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

@ -39,22 +39,34 @@ add_task(function *() {
names = names.map(element => element.textContent);
ok(names.includes(SERVICE_WORKER), "The service worker url appears in the list: " + names);
// Finally, unregister the service worker itself
let aboutDebuggingUpdate = waitForWorkersUpdate(document);
// Use message manager to work with e10s
let frameScript = function () {
// Retrieve the `sw` promise created in the html page
let { sw } = content.wrappedJSObject;
sw.then(function (registration) {
registration.unregister().then(function (success) {
dump("SW unregistered: " + success + "\n");
sendAsyncMessage("sw-unregistered");
},
function (e) {
dump("SW not unregistered; " + e + "\n");
});
});
};
swTab.linkedBrowser.messageManager.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
let mm = swTab.linkedBrowser.messageManager;
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
yield waitForWorkersUpdate(document);
yield new Promise(done => {
mm.addMessageListener("sw-unregistered", function listener() {
mm.removeMessageListener("sw-unregistered", listener);
done();
});
});
ok(true, "Service worker registration unregistered");
yield aboutDebuggingUpdate;
// Check that the service worker disappeared from the UI
names = [...document.querySelectorAll("#service-workers .target-name")];

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

@ -98,14 +98,23 @@ add_task(function *() {
let { sw } = content.wrappedJSObject;
sw.then(function (registration) {
registration.unregister().then(function (success) {
dump("SW unregistered: " + success + "\n");
sendAsyncMessage("sw-unregistered");
},
function (e) {
dump("SW not unregistered; " + e + "\n");
});
});
};
swTab.linkedBrowser.messageManager.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
let mm = swTab.linkedBrowser.messageManager;
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
yield new Promise(done => {
mm.addMessageListener("sw-unregistered", function listener() {
mm.removeMessageListener("sw-unregistered", listener);
done();
});
});
ok(true, "Service worker registration unregistered");
yield removeTab(swTab);
yield closeAboutDebugging(tab);

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

@ -93,7 +93,9 @@ var getServerTraits = Task.async(function*(target) {
{ name: "hasSetCurrentTimes", actor: "animations",
method: "setCurrentTimes" },
{ name: "hasGetFrames", actor: "animationplayer",
method: "getFrames" }
method: "getFrames" },
{ name: "hasSetWalkerActor", actor: "animations",
method: "setWalkerActor" },
];
let traits = {};
@ -147,6 +149,12 @@ var AnimationsController = {
return;
}
// Let the AnimationsActor know what WalkerActor we're using. This will
// come in handy later to return references to DOM Nodes.
if (this.traits.hasSetWalkerActor) {
yield this.animationsFront.setWalkerActor(gInspector.walker);
}
this.startListeners();
yield this.onNewNodeFront();

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

@ -3,35 +3,22 @@
const {Cu} = require("chrome");
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
const {
createNode,
TargetNodeHighlighter
} = require("devtools/client/animationinspector/utils");
const {DomNodePreview} = require(
"devtools/client/inspector/shared/dom-node-preview");
const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
const L10N = new ViewHelpers.L10N(STRINGS_URI);
// Map dom node fronts by animation fronts so we don't have to get them from the
// walker every time the timeline is refreshed.
var nodeFronts = new WeakMap();
/**
* UI component responsible for displaying a preview of the target dom node of
* a given animation.
* @param {InspectorPanel} inspector Requires a reference to the inspector-panel
* to highlight and select the node, as well as refresh it when there are
* mutations.
* @param {Object} options Supported properties are:
* - compact {Boolean} Defaults to false. If true, nodes will be previewed like
* tag#id.class instead of <tag id="id" class="class">
* Accepts the same parameters as the DomNodePreview component. See
* devtools/client/inspector/shared/dom-node-preview.js for documentation.
*/
function AnimationTargetNode(inspector, options = {}) {
function AnimationTargetNode(inspector, options) {
this.inspector = inspector;
this.options = options;
this.onPreviewMouseOver = this.onPreviewMouseOver.bind(this);
this.onPreviewMouseOut = this.onPreviewMouseOut.bind(this);
this.onSelectNodeClick = this.onSelectNodeClick.bind(this);
this.onMarkupMutations = this.onMarkupMutations.bind(this);
this.onHighlightNodeClick = this.onHighlightNodeClick.bind(this);
this.onTargetHighlighterLocked = this.onTargetHighlighterLocked.bind(this);
this.previewer = new DomNodePreview(inspector, options);
EventEmitter.decorate(this);
}
@ -39,282 +26,51 @@ exports.AnimationTargetNode = AnimationTargetNode;
AnimationTargetNode.prototype = {
init: function(containerEl) {
let document = containerEl.ownerDocument;
// Init the markup for displaying the target node.
this.el = createNode({
parent: containerEl,
attributes: {
"class": "animation-target"
}
});
// Icon to select the node in the inspector.
this.highlightNodeEl = createNode({
parent: this.el,
nodeType: "span",
attributes: {
"class": "node-highlighter",
"title": L10N.getStr("node.highlightNodeLabel")
}
});
// Wrapper used for mouseover/out event handling.
this.previewEl = createNode({
parent: this.el,
nodeType: "span",
attributes: {
"title": L10N.getStr("node.selectNodeLabel")
}
});
if (!this.options.compact) {
this.previewEl.appendChild(document.createTextNode("<"));
}
// Tag name.
this.tagNameEl = createNode({
parent: this.previewEl,
nodeType: "span",
attributes: {
"class": "tag-name theme-fg-color3"
}
});
// Id attribute container.
this.idEl = createNode({
parent: this.previewEl,
nodeType: "span"
});
if (!this.options.compact) {
createNode({
parent: this.idEl,
nodeType: "span",
attributes: {
"class": "attribute-name theme-fg-color2"
},
textContent: "id"
});
this.idEl.appendChild(document.createTextNode("=\""));
} else {
createNode({
parent: this.idEl,
nodeType: "span",
attributes: {
"class": "theme-fg-color2"
},
textContent: "#"
});
}
createNode({
parent: this.idEl,
nodeType: "span",
attributes: {
"class": "attribute-value theme-fg-color6"
}
});
if (!this.options.compact) {
this.idEl.appendChild(document.createTextNode("\""));
}
// Class attribute container.
this.classEl = createNode({
parent: this.previewEl,
nodeType: "span"
});
if (!this.options.compact) {
createNode({
parent: this.classEl,
nodeType: "span",
attributes: {
"class": "attribute-name theme-fg-color2"
},
textContent: "class"
});
this.classEl.appendChild(document.createTextNode("=\""));
} else {
createNode({
parent: this.classEl,
nodeType: "span",
attributes: {
"class": "theme-fg-color6"
},
textContent: "."
});
}
createNode({
parent: this.classEl,
nodeType: "span",
attributes: {
"class": "attribute-value theme-fg-color6"
}
});
if (!this.options.compact) {
this.classEl.appendChild(document.createTextNode("\""));
this.previewEl.appendChild(document.createTextNode(">"));
}
this.startListeners();
},
startListeners: function() {
// Init events for highlighting and selecting the node.
this.previewEl.addEventListener("mouseover", this.onPreviewMouseOver);
this.previewEl.addEventListener("mouseout", this.onPreviewMouseOut);
this.previewEl.addEventListener("click", this.onSelectNodeClick);
this.highlightNodeEl.addEventListener("click", this.onHighlightNodeClick);
// Start to listen for markupmutation events.
this.inspector.on("markupmutation", this.onMarkupMutations);
// Listen to the target node highlighter.
TargetNodeHighlighter.on("highlighted", this.onTargetHighlighterLocked);
},
stopListeners: function() {
TargetNodeHighlighter.off("highlighted", this.onTargetHighlighterLocked);
this.inspector.off("markupmutation", this.onMarkupMutations);
this.previewEl.removeEventListener("mouseover", this.onPreviewMouseOver);
this.previewEl.removeEventListener("mouseout", this.onPreviewMouseOut);
this.previewEl.removeEventListener("click", this.onSelectNodeClick);
this.highlightNodeEl.removeEventListener("click", this.onHighlightNodeClick);
this.previewer.init(containerEl);
this.isDestroyed = false;
},
destroy: function() {
TargetNodeHighlighter.unhighlight().catch(e => console.error(e));
this.stopListeners();
this.el.remove();
this.el = this.tagNameEl = this.idEl = this.classEl = null;
this.highlightNodeEl = this.previewEl = null;
this.nodeFront = this.inspector = this.playerFront = null;
},
get highlighterUtils() {
if (this.inspector && this.inspector.toolbox) {
return this.inspector.toolbox.highlighterUtils;
}
return null;
},
onPreviewMouseOver: function() {
if (!this.nodeFront || !this.highlighterUtils) {
return;
}
this.highlighterUtils.highlightNodeFront(this.nodeFront)
.catch(e => console.error(e));
},
onPreviewMouseOut: function() {
if (!this.nodeFront || !this.highlighterUtils) {
return;
}
this.highlighterUtils.unhighlight()
.catch(e => console.error(e));
},
onSelectNodeClick: function() {
if (!this.nodeFront) {
return;
}
this.inspector.selection.setNodeFront(this.nodeFront, "animationinspector");
},
onHighlightNodeClick: function(e) {
e.stopPropagation();
let classList = this.highlightNodeEl.classList;
let isHighlighted = classList.contains("selected");
if (isHighlighted) {
classList.remove("selected");
TargetNodeHighlighter.unhighlight().then(() => {
this.emit("target-highlighter-unlocked");
}, e => console.error(e));
} else {
classList.add("selected");
TargetNodeHighlighter.highlight(this).then(() => {
this.emit("target-highlighter-locked");
}, e => console.error(e));
}
},
onTargetHighlighterLocked: function(e, animationTargetNode) {
if (animationTargetNode !== this) {
this.highlightNodeEl.classList.remove("selected");
}
},
onMarkupMutations: function(e, mutations) {
if (!this.nodeFront || !this.playerFront) {
return;
}
for (let {target} of mutations) {
if (target === this.nodeFront) {
// Re-render with the same nodeFront to update the output.
this.render(this.playerFront);
break;
}
}
this.previewer.destroy();
this.inspector = null;
this.isDestroyed = true;
},
render: Task.async(function*(playerFront) {
this.playerFront = playerFront;
this.nodeFront = undefined;
// Get the nodeFront from the cache if it was stored previously.
let nodeFront = nodeFronts.get(playerFront);
try {
this.nodeFront = yield this.inspector.walker.getNodeFromActor(
playerFront.actorID, ["node"]);
} catch (e) {
if (!this.el) {
// The panel was destroyed in the meantime. Just log a warning.
console.warn("Cound't retrieve the animation target node, widget " +
"destroyed");
} else {
// This was an unexpected error, log it.
console.error(e);
}
return;
// Try and get it from the playerFront directly next.
if (!nodeFront) {
nodeFront = playerFront.animationTargetNodeFront;
}
if (!this.nodeFront || !this.el) {
return;
}
let {tagName, attributes} = this.nodeFront;
this.tagNameEl.textContent = tagName.toLowerCase();
let idIndex = attributes.findIndex(({name}) => name === "id");
if (idIndex > -1 && attributes[idIndex].value) {
this.idEl.querySelector(".attribute-value").textContent =
attributes[idIndex].value;
this.idEl.style.display = "inline";
} else {
this.idEl.style.display = "none";
}
let classIndex = attributes.findIndex(({name}) => name === "class");
if (classIndex > -1 && attributes[classIndex].value) {
let value = attributes[classIndex].value;
if (this.options.compact) {
value = value.split(" ").join(".");
// Finally, get it from the walkerActor if it wasn't found.
if (!nodeFront) {
try {
nodeFront = yield this.inspector.walker.getNodeFromActor(
playerFront.actorID, ["node"]);
} catch (e) {
// If an error occured while getting the nodeFront and if it can't be
// attributed to the panel having been destroyed in the meantime, this
// error needs to be logged and render needs to stop.
if (!this.isDestroyed) {
console.error(e);
}
return;
}
this.classEl.querySelector(".attribute-value").textContent = value;
this.classEl.style.display = "inline";
} else {
this.classEl.style.display = "none";
// In all cases, if by now the panel doesn't exist anymore, we need to
// stop rendering too.
if (this.isDestroyed) {
return;
}
}
// Add the nodeFront to the cache.
nodeFronts.set(playerFront, nodeFront);
this.previewer.render(nodeFront);
this.emit("target-retrieved");
})
};

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

@ -25,7 +25,7 @@ add_task(function*() {
// Reduce the known nodeFronts to a set to make them unique.
let nodeFronts = new Set(panel.animationsTimelineComponent
.targetNodes.map(n => n.nodeFront));
.targetNodes.map(n => n.previewer.nodeFront));
is(nodeFronts.size, 3,
"The animations are applied to 3 different node fronts");
});

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

@ -16,16 +16,18 @@ add_task(function*() {
yield selectNode(".animated", inspector);
let targetNodeComponent = panel.animationsTimelineComponent.targetNodes[0];
let {previewer} = targetNodeComponent;
// Make sure to wait for the target-retrieved event if the nodeFront hasn't
// yet been retrieved by the TargetNodeComponent.
if (!targetNodeComponent.nodeFront) {
if (!previewer.nodeFront) {
yield targetNodeComponent.once("target-retrieved");
}
is(targetNodeComponent.el.textContent, "div#.ball.animated",
is(previewer.el.textContent, "div#.ball.animated",
"The target element's content is correct");
let highlighterEl = targetNodeComponent.el.querySelector(".node-highlighter");
let highlighterEl = previewer.el.querySelector(".node-highlighter");
ok(highlighterEl,
"The icon to highlight the target element in the page exists");
});

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

@ -24,7 +24,7 @@ add_task(function*() {
let targetNodeComponent = targets[0];
info("Retrieve the part of the widget that highlights the node on hover");
let highlightingEl = targetNodeComponent.previewEl;
let highlightingEl = targetNodeComponent.previewer.previewEl;
info("Listen to node-highlight event and mouse over the widget");
let onHighlight = toolbox.once("node-highlight");
@ -39,7 +39,7 @@ add_task(function*() {
highlightingEl.ownerDocument.defaultView);
ok(true, "The node-highlight event was fired");
is(targetNodeComponent.nodeFront, nodeFront,
is(targetNodeComponent.previewer.nodeFront, nodeFront,
"The highlighted node is the one stored on the animation widget");
is(nodeFront.tagName, "DIV",
"The highlighted node has the correct tagName");
@ -60,12 +60,12 @@ add_task(function*() {
"selection to change");
let onSelection = inspector.selection.once("new-node-front");
onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
let nodeEl = targetNodeComponent.previewEl;
let nodeEl = targetNodeComponent.previewer.previewEl;
EventUtils.sendMouseEvent({type: "click"}, nodeEl,
nodeEl.ownerDocument.defaultView);
yield onSelection;
is(inspector.selection.nodeFront, targetNodeComponent.nodeFront,
is(inspector.selection.nodeFront, targetNodeComponent.previewer.nodeFront,
"The selected node is the one stored on the animation widget");
yield onPanelUpdated;

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

@ -11,42 +11,44 @@ requestLongerTimeout(2);
add_task(function*() {
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
let {toolbox, inspector, panel} = yield openAnimationInspector();
let {panel} = yield openAnimationInspector();
let targets = panel.animationsTimelineComponent.targetNodes;
info("Click on the highlighter icon for the first animated node");
yield lockHighlighterOn(targets[0]);
ok(targets[0].highlightNodeEl.classList.contains("selected"),
let domNodePreview1 = targets[0].previewer;
yield lockHighlighterOn(domNodePreview1);
ok(domNodePreview1.highlightNodeEl.classList.contains("selected"),
"The highlighter icon is selected");
info("Click on the highlighter icon for the second animated node");
yield lockHighlighterOn(targets[1]);
ok(targets[1].highlightNodeEl.classList.contains("selected"),
let domNodePreview2 = targets[1].previewer;
yield lockHighlighterOn(domNodePreview2);
ok(domNodePreview2.highlightNodeEl.classList.contains("selected"),
"The highlighter icon is selected");
ok(!targets[0].highlightNodeEl.classList.contains("selected"),
ok(!domNodePreview1.highlightNodeEl.classList.contains("selected"),
"The highlighter icon for the first node is unselected");
info("Click again to unhighlight");
yield unlockHighlighterOn(targets[1]);
ok(!targets[1].highlightNodeEl.classList.contains("selected"),
yield unlockHighlighterOn(domNodePreview2);
ok(!domNodePreview2.highlightNodeEl.classList.contains("selected"),
"The highlighter icon for the second node is unselected");
});
function* lockHighlighterOn(targetComponent) {
let onLocked = targetComponent.once("target-highlighter-locked");
clickOnHighlighterIcon(targetComponent);
function* lockHighlighterOn(domNodePreview) {
let onLocked = domNodePreview.once("target-highlighter-locked");
clickOnHighlighterIcon(domNodePreview);
yield onLocked;
}
function* unlockHighlighterOn(targetComponent) {
let onUnlocked = targetComponent.once("target-highlighter-unlocked");
clickOnHighlighterIcon(targetComponent);
function* unlockHighlighterOn(domNodePreview) {
let onUnlocked = domNodePreview.once("target-highlighter-unlocked");
clickOnHighlighterIcon(domNodePreview);
yield onUnlocked;
}
function clickOnHighlighterIcon(targetComponent) {
let lockEl = targetComponent.highlightNodeEl;
function clickOnHighlighterIcon(domNodePreview) {
let lockEl = domNodePreview.highlightNodeEl;
EventUtils.sendMouseEvent({type: "click"}, lockEl,
lockEl.ownerDocument.defaultView);
}

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

@ -351,7 +351,7 @@ function isNodeVisible(node) {
var waitForAllAnimationTargets = Task.async(function*(panel) {
let targets = panel.animationsTimelineComponent.targetNodes;
yield promise.all(targets.map(t => {
if (!t.nodeFront) {
if (!t.previewer.nodeFront) {
return t.once("target-retrieved");
}
return false;

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

@ -146,43 +146,6 @@ function findOptimalTimeInterval(timeScale,
exports.findOptimalTimeInterval = findOptimalTimeInterval;
/**
* The TargetNodeHighlighter util is a helper for AnimationTargetNode components
* that is used to lock the highlighter on animated nodes in the page.
* It instantiates a new highlighter that is then shared amongst all instances
* of AnimationTargetNode. This is useful because that means showing the
* highlighter on one animated node will unhighlight the previously highlighted
* one, but will not interfere with the default inspector highlighter.
*/
var TargetNodeHighlighter = {
highlighter: null,
isShown: false,
highlight: Task.async(function*(animationTargetNode) {
if (!this.highlighter) {
let hUtils = animationTargetNode.inspector.toolbox.highlighterUtils;
this.highlighter = yield hUtils.getHighlighterByType("BoxModelHighlighter");
}
yield this.highlighter.show(animationTargetNode.nodeFront);
this.isShown = true;
this.emit("highlighted", animationTargetNode);
}),
unhighlight: Task.async(function*() {
if (!this.highlighter || !this.isShown) {
return;
}
yield this.highlighter.hide();
this.isShown = false;
this.emit("unhighlighted");
})
};
EventEmitter.decorate(TargetNodeHighlighter);
exports.TargetNodeHighlighter = TargetNodeHighlighter;
/**
* Format a timestamp (in ms) as a mm:ss.mmm string.
* @param {Number} time

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

@ -12,8 +12,10 @@ const TEST_URI = "<style>" +
"#div1 { margin-top: 5px }" +
"#div2 { border-bottom: 1em solid black; }" +
"#div3 { padding: 2em; }" +
"#div4 { margin: 1px; }" +
"</style>" +
"<div id='div1'></div><div id='div2'></div><div id='div3'></div>";
"<div id='div1'></div><div id='div2'></div>" +
"<div id='div3'></div><div id='div4'></div>";
function getStyle(node, property) {
return node.style.getPropertyValue(property);
@ -144,3 +146,34 @@ function*(inspector, view) {
is(getStyle(node, "margin-right"), "", "Should be the right margin-top on the element.")
is(span.textContent, 10, "Should have the right value in the box model.");
});
addTest("Test that clicking in the editor input does not remove focus",
function*(inspector, view) {
let node = content.document.getElementById("div4");
yield selectNode("#div4", inspector);
let span = view.doc.querySelector(".margin.top > span");
is(span.textContent, 1, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
let editor = view.doc.querySelector(".styleinspector-propertyeditor");
ok(editor, "Should have opened the editor.");
info("Click in the already opened editor input");
EventUtils.synthesizeMouseAtCenter(editor, {}, view.doc.defaultView);
is(editor, view.doc.activeElement,
"Inplace editor input should still have focus.");
info("Check the input can still be used as expected");
EventUtils.synthesizeKey("VK_UP", {}, view.doc.defaultView);
yield waitForUpdate(inspector);
is(editor.value, "2px", "Should have the right value in the editor.");
is(getStyle(node, "margin-top"), "2px", "Should have updated the margin.");
EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
is(getStyle(node, "margin-top"), "2px",
"Should be the right margin-top on the element.");
is(span.textContent, 2, "Should have the right value in the box model.");
});

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

@ -39,6 +39,8 @@ XPCOMUtils.defineLazyGetter(this, "domUtils", function() {
* inherited: An element this rule was inherited from. If omitted,
* the rule applies directly to the current element.
* isSystem: Is this a user agent style?
* isUnmatched: True if the rule does not match the current selected
* element, otherwise, false.
*/
function Rule(elementStyle, options) {
this.elementStyle = elementStyle;
@ -48,6 +50,7 @@ function Rule(elementStyle, options) {
this.pseudoElement = options.pseudoElement || "";
this.isSystem = options.isSystem;
this.isUnmatched = options.isUnmatched || false;
this.inherited = options.inherited || null;
this.keyframes = options.keyframes || null;
this._modificationDepth = 0;

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

@ -101,6 +101,7 @@ skip-if = e10s # Bug 1039528: "inspect element" contextual-menu doesn't work wit
[browser_rules_edit-selector_04.js]
[browser_rules_edit-selector_05.js]
[browser_rules_edit-selector_06.js]
[browser_rules_edit-selector_07.js]
[browser_rules_editable-field-focus_01.js]
[browser_rules_editable-field-focus_02.js]
[browser_rules_eyedropper.js]

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

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that the rule view overridden search filter does not appear for an
// unmatched rule.
const TEST_URI = `
<style type="text/css">
div {
height: 0px;
}
#testid {
height: 1px;
}
.testclass {
height: 10px;
}
</style>
<div id="testid">Styled Node</div>
<span class="testclass">This is a span</span>
`;
add_task(function*() {
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
yield selectNode("#testid", inspector);
yield testEditSelector(view, "span");
});
function* testEditSelector(view, name) {
info("Test editing existing selector fields");
let ruleEditor = getRuleViewRuleEditor(view, 1);
info("Focusing an existing selector name in the rule-view");
let editor = yield focusEditableField(view, ruleEditor.selectorText);
is(inplaceEditor(ruleEditor.selectorText), editor,
"The selector editor got focused");
info("Entering a new selector name and committing");
editor.input.value = name;
info("Entering the commit key");
let onRuleViewChanged = once(view, "ruleview-changed");
EventUtils.synthesizeKey("VK_RETURN", {});
yield onRuleViewChanged;
// Get the new rule editor that replaced the original
ruleEditor = getRuleViewRuleEditor(view, 1);
let rule = ruleEditor.rule;
let textPropEditor = rule.textProps[0].editor;
is(view._elementStyle.rules.length, 3, "Should have 3 rules.");
ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
ok(ruleEditor.element.getAttribute("unmatched"),
"Rule with " + name + " does not match the current element.");
ok(textPropEditor.filterProperty.hidden, "Overridden search is hidden.");
}

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

@ -48,6 +48,8 @@ const TEST_DATA = [
numUserRules: 1,
numUARules: 0
},
// Note that some tests below assume that the "a" selector is the
// last test in TEST_DATA.
{
selector: "a",
numUserRules: 3,
@ -111,9 +113,11 @@ function* userAgentStylesVisible(inspector, view) {
ok(userRules.some(rule=> rule.matchedSelectors.length === 1),
"There is an inline style for element in user styles");
ok(uaRules.some(rule=> rule.matchedSelectors.indexOf(":-moz-any-link")),
// These tests rely on the "a" selector being the last test in
// TEST_DATA.
ok(uaRules.some(rule=> rule.matchedSelectors.indexOf(":-moz-any-link") !== -1),
"There is a rule for :-moz-any-link");
ok(uaRules.some(rule=> rule.matchedSelectors.indexOf("*|*:link")),
ok(uaRules.some(rule=> rule.matchedSelectors.indexOf("*|*:link") !== -1),
"There is a rule for *|*:link");
ok(uaRules.some(rule=> rule.matchedSelectors.length === 1),
"Inline styles for ua styles");

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

@ -5,16 +5,16 @@
<title>authored sheet test</title>
<style>
#target {
color: chartreuse;
}
pre a {
color: orange;
}
</style>
<script>
var gIOService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
.getService(SpecialPowers.Ci.nsIIOService)
var style = "data:text/css,div { background-color: seagreen; }";
var style = "data:text/css,a { background-color: seagreen; }";
var uri = gIOService.newURI(style, null, null);
var windowUtils = SpecialPowers.wrap(window)
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
@ -25,8 +25,6 @@ windowUtils.loadSheet(uri, windowUtils.AUTHOR_SHEET);
</head>
<body>
<div id="target"> the ocean </div>
<input type=text placeholder=test></input>
<input type=color></input>
<input type=range></input>

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

@ -86,6 +86,7 @@ RuleEditor.prototype = {
this.element = this.doc.createElementNS(HTML_NS, "div");
this.element.className = "ruleview-rule theme-separator";
this.element.setAttribute("uneditable", !this.isEditable);
this.element.setAttribute("unmatched", this.rule.isUnmatched);
this.element._ruleEditor = this;
// Give a relative position for the inplace editor's measurement
@ -494,6 +495,7 @@ RuleEditor.prototype = {
return;
}
ruleProps.isUnmatched = !isMatching;
let newRule = new Rule(elementStyle, ruleProps);
let editor = new RuleEditor(ruleView, newRule);
let rules = elementStyle.rules;
@ -503,7 +505,6 @@ RuleEditor.prototype = {
elementStyle._changed();
elementStyle.markOverriddenAll();
editor.element.setAttribute("unmatched", !isMatching);
this.element.parentNode.replaceChild(editor.element, this.element);
// Remove highlight for modified selector

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

@ -299,7 +299,8 @@ TextPropertyEditor.prototype = {
this.warning.hidden = this.editing || this.isValid();
this.filterProperty.hidden = this.editing ||
!this.isValid() ||
!this.prop.overridden;
!this.prop.overridden ||
this.ruleEditor.rule.isUnmatched;
if (!this.editing &&
(this.prop.overridden || !this.prop.enabled ||

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

@ -0,0 +1,333 @@
/* 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/. */
"use strict";
const {Cu} = require("chrome");
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
const {createNode} = require("devtools/client/animationinspector/utils");
const STRINGS_URI = "chrome://devtools/locale/inspector.properties";
const L10N = new ViewHelpers.L10N(STRINGS_URI);
/**
* UI component responsible for displaying a preview of a dom node.
* @param {InspectorPanel} inspector Requires a reference to the inspector-panel
* to highlight and select the node, as well as refresh it when there are
* mutations.
* @param {Object} options Supported properties are:
* - compact {Boolean} Defaults to false.
* By default, nodes are previewed like <tag id="id" class="class">
* If true, nodes will be previewed like tag#id.class instead.
*/
function DomNodePreview(inspector, options = {}) {
this.inspector = inspector;
this.options = options;
this.onPreviewMouseOver = this.onPreviewMouseOver.bind(this);
this.onPreviewMouseOut = this.onPreviewMouseOut.bind(this);
this.onSelectElClick = this.onSelectElClick.bind(this);
this.onMarkupMutations = this.onMarkupMutations.bind(this);
this.onHighlightElClick = this.onHighlightElClick.bind(this);
this.onHighlighterLocked = this.onHighlighterLocked.bind(this);
EventEmitter.decorate(this);
}
exports.DomNodePreview = DomNodePreview;
DomNodePreview.prototype = {
init: function(containerEl) {
let document = containerEl.ownerDocument;
// Init the markup for displaying the target node.
this.el = createNode({
parent: containerEl,
attributes: {
"class": "animation-target"
}
});
// Icon to select the node in the inspector.
this.highlightNodeEl = createNode({
parent: this.el,
nodeType: "span",
attributes: {
"class": "node-highlighter",
"title": L10N.getStr("inspector.nodePreview.highlightNodeLabel")
}
});
// Wrapper used for mouseover/out event handling.
this.previewEl = createNode({
parent: this.el,
nodeType: "span",
attributes: {
"title": L10N.getStr("inspector.nodePreview.selectNodeLabel")
}
});
if (!this.options.compact) {
this.previewEl.appendChild(document.createTextNode("<"));
}
// Tag name.
this.tagNameEl = createNode({
parent: this.previewEl,
nodeType: "span",
attributes: {
"class": "tag-name theme-fg-color3"
}
});
// Id attribute container.
this.idEl = createNode({
parent: this.previewEl,
nodeType: "span"
});
if (!this.options.compact) {
createNode({
parent: this.idEl,
nodeType: "span",
attributes: {
"class": "attribute-name theme-fg-color2"
},
textContent: "id"
});
this.idEl.appendChild(document.createTextNode("=\""));
} else {
createNode({
parent: this.idEl,
nodeType: "span",
attributes: {
"class": "theme-fg-color6"
},
textContent: "#"
});
}
createNode({
parent: this.idEl,
nodeType: "span",
attributes: {
"class": "attribute-value theme-fg-color6"
}
});
if (!this.options.compact) {
this.idEl.appendChild(document.createTextNode("\""));
}
// Class attribute container.
this.classEl = createNode({
parent: this.previewEl,
nodeType: "span"
});
if (!this.options.compact) {
createNode({
parent: this.classEl,
nodeType: "span",
attributes: {
"class": "attribute-name theme-fg-color2"
},
textContent: "class"
});
this.classEl.appendChild(document.createTextNode("=\""));
} else {
createNode({
parent: this.classEl,
nodeType: "span",
attributes: {
"class": "theme-fg-color6"
},
textContent: "."
});
}
createNode({
parent: this.classEl,
nodeType: "span",
attributes: {
"class": "attribute-value theme-fg-color6"
}
});
if (!this.options.compact) {
this.classEl.appendChild(document.createTextNode("\""));
this.previewEl.appendChild(document.createTextNode(">"));
}
this.startListeners();
},
startListeners: function() {
// Init events for highlighting and selecting the node.
this.previewEl.addEventListener("mouseover", this.onPreviewMouseOver);
this.previewEl.addEventListener("mouseout", this.onPreviewMouseOut);
this.previewEl.addEventListener("click", this.onSelectElClick);
this.highlightNodeEl.addEventListener("click", this.onHighlightElClick);
// Start to listen for markupmutation events.
this.inspector.on("markupmutation", this.onMarkupMutations);
// Listen to the target node highlighter.
HighlighterLock.on("highlighted", this.onHighlighterLocked);
},
stopListeners: function() {
HighlighterLock.off("highlighted", this.onHighlighterLocked);
this.inspector.off("markupmutation", this.onMarkupMutations);
this.previewEl.removeEventListener("mouseover", this.onPreviewMouseOver);
this.previewEl.removeEventListener("mouseout", this.onPreviewMouseOut);
this.previewEl.removeEventListener("click", this.onSelectElClick);
this.highlightNodeEl.removeEventListener("click", this.onHighlightElClick);
},
destroy: function() {
HighlighterLock.unhighlight().catch(e => console.error(e));
this.stopListeners();
this.el.remove();
this.el = this.tagNameEl = this.idEl = this.classEl = null;
this.highlightNodeEl = this.previewEl = null;
this.nodeFront = this.inspector = null;
},
get highlighterUtils() {
if (this.inspector && this.inspector.toolbox) {
return this.inspector.toolbox.highlighterUtils;
}
return null;
},
onPreviewMouseOver: function() {
if (!this.nodeFront || !this.highlighterUtils) {
return;
}
this.highlighterUtils.highlightNodeFront(this.nodeFront)
.catch(e => console.error(e));
},
onPreviewMouseOut: function() {
if (!this.nodeFront || !this.highlighterUtils) {
return;
}
this.highlighterUtils.unhighlight()
.catch(e => console.error(e));
},
onSelectElClick: function() {
if (!this.nodeFront) {
return;
}
this.inspector.selection.setNodeFront(this.nodeFront, "dom-node-preview");
},
onHighlightElClick: function(e) {
e.stopPropagation();
let classList = this.highlightNodeEl.classList;
let isHighlighted = classList.contains("selected");
if (isHighlighted) {
classList.remove("selected");
HighlighterLock.unhighlight().then(() => {
this.emit("target-highlighter-unlocked");
}, error => console.error(error));
} else {
classList.add("selected");
HighlighterLock.highlight(this).then(() => {
this.emit("target-highlighter-locked");
}, error => console.error(error));
}
},
onHighlighterLocked: function(e, domNodePreview) {
if (domNodePreview !== this) {
this.highlightNodeEl.classList.remove("selected");
}
},
onMarkupMutations: function(e, mutations) {
if (!this.nodeFront) {
return;
}
for (let {target} of mutations) {
if (target === this.nodeFront) {
// Re-render with the same nodeFront to update the output.
this.render(this.nodeFront);
break;
}
}
},
render: function(nodeFront) {
this.nodeFront = nodeFront;
let {tagName, attributes} = nodeFront;
this.tagNameEl.textContent = tagName.toLowerCase();
let idIndex = attributes.findIndex(({name}) => name === "id");
if (idIndex > -1 && attributes[idIndex].value) {
this.idEl.querySelector(".attribute-value").textContent =
attributes[idIndex].value;
this.idEl.style.display = "inline";
} else {
this.idEl.style.display = "none";
}
let classIndex = attributes.findIndex(({name}) => name === "class");
if (classIndex > -1 && attributes[classIndex].value) {
let value = attributes[classIndex].value;
if (this.options.compact) {
value = value.split(" ").join(".");
}
this.classEl.querySelector(".attribute-value").textContent = value;
this.classEl.style.display = "inline";
} else {
this.classEl.style.display = "none";
}
}
};
/**
* HighlighterLock is a helper used to lock the highlighter on DOM nodes in the
* page.
* It instantiates a new highlighter that is then shared amongst all instances
* of DomNodePreview. This is useful because that means showing the highlighter
* on one node will unhighlight the previously highlighted one, but will not
* interfere with the default inspector highlighter.
*/
var HighlighterLock = {
highlighter: null,
isShown: false,
highlight: Task.async(function*(animationTargetNode) {
if (!this.highlighter) {
let util = animationTargetNode.inspector.toolbox.highlighterUtils;
this.highlighter = yield util.getHighlighterByType("BoxModelHighlighter");
}
yield this.highlighter.show(animationTargetNode.nodeFront);
this.isShown = true;
this.emit("highlighted", animationTargetNode);
}),
unhighlight: Task.async(function*() {
if (!this.highlighter || !this.isShown) {
return;
}
yield this.highlighter.hide();
this.isShown = false;
this.emit("unhighlighted");
})
};
EventEmitter.decorate(HighlighterLock);

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

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'dom-node-preview.js',
'style-inspector-menu.js',
'style-inspector-overlays.js',
'utils.js'

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

@ -32,11 +32,16 @@ const TOOLTIP_IMAGE_TYPE = "image";
const TOOLTIP_FONTFAMILY_TYPE = "font-family";
// Types of nodes in the rule/computed-view
const VIEW_NODE_SELECTOR_TYPE = exports.VIEW_NODE_SELECTOR_TYPE = 1;
const VIEW_NODE_PROPERTY_TYPE = exports.VIEW_NODE_PROPERTY_TYPE = 2;
const VIEW_NODE_VALUE_TYPE = exports.VIEW_NODE_VALUE_TYPE = 3;
const VIEW_NODE_IMAGE_URL_TYPE = exports.VIEW_NODE_IMAGE_URL_TYPE = 4;
const VIEW_NODE_LOCATION_TYPE = exports.VIEW_NODE_LOCATION_TYPE = 5;
const VIEW_NODE_SELECTOR_TYPE = 1;
exports.VIEW_NODE_SELECTOR_TYPE = VIEW_NODE_SELECTOR_TYPE;
const VIEW_NODE_PROPERTY_TYPE = 2;
exports.VIEW_NODE_PROPERTY_TYPE = VIEW_NODE_PROPERTY_TYPE;
const VIEW_NODE_VALUE_TYPE = 3;
exports.VIEW_NODE_VALUE_TYPE = VIEW_NODE_VALUE_TYPE;
const VIEW_NODE_IMAGE_URL_TYPE = 4;
exports.VIEW_NODE_IMAGE_URL_TYPE = VIEW_NODE_IMAGE_URL_TYPE;
const VIEW_NODE_LOCATION_TYPE = 5;
exports.VIEW_NODE_LOCATION_TYPE = VIEW_NODE_LOCATION_TYPE;
/**
* Manages all highlighters in the style-inspector.
@ -183,9 +188,9 @@ HighlightersOverlay.prototype = {
// promise. This causes some tests to fail when trying to install a
// rejection handler on the result of the call. To avoid this, check
// whether the result is truthy before installing the handler.
let promise = this.highlighters[this.highlighterShown].hide();
if (promise) {
promise.then(null, e => console.error(e));
let onHidden = this.highlighters[this.highlighterShown].hide();
if (onHidden) {
onHidden.then(null, e => console.error(e));
}
this.highlighterShown = null;

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

@ -6,7 +6,7 @@
"use strict";
const {Cc, Ci, Cu} = require("chrome");
const {Ci, Cu} = require("chrome");
const {setTimeout, clearTimeout} =
Cu.import("resource://gre/modules/Timer.jsm", {});
const {parseDeclarations} =
@ -28,7 +28,7 @@ const HTML_NS = "http://www.w3.org/1999/xhtml";
* @param {object} attributes
* A set of attributes to set on the node.
*/
function createChild(parent, tagName, attributes={}) {
function createChild(parent, tagName, attributes = {}) {
let elt = parent.ownerDocument.createElementNS(HTML_NS, tagName);
for (let attr in attributes) {
if (attributes.hasOwnProperty(attr)) {

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

@ -93,17 +93,3 @@ timeline.csstransition.nameLabel=%S - CSS Transition
# This can happen if devtools couldn't figure out the type of the animation.
# %S will be replaced by the name of the transition at run-time.
timeline.unknown.nameLabel=%S
# LOCALIZATION NOTE (node.selectNodeLabel):
# This string is displayed in a tooltip of the animation panel that is shown
# when hovering over an animated node (e.g. something like div.animated).
# The tooltip invites the user to click on the node in order to select it in the
# inspector panel.
node.selectNodeLabel=Click to select this node in the Inspector
# LOCALIZATION NOTE (node.highlightNodeLabel):
# This string is displayed in a tooltip of the animation panel that is shown
# when hovering over the inspector icon displayed next to animated nodes.
# The tooltip invites the user to click on the icon in order to show the node
# highlighter.
node.highlightNodeLabel=Click to highlight this node in the page

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

@ -116,3 +116,22 @@ inspector.menu.editAttribute.label=Edit Attribute %S
# when the user right-clicks on the attribute of a node in the inspector,
# and that allows to remove this attribute.
inspector.menu.removeAttribute.label=Remove Attribute %S
# LOCALIZATION NOTE (inspector.nodePreview.selectNodeLabel):
# This string is displayed in a tooltip that is shown when hovering over a DOM
# node preview (e.g. something like "div#foo.bar").
# DOM node previews can be displayed in places like the animation-inspector, the
# console or the object inspector.
# The tooltip invites the user to click on the node in order to select it in the
# inspector panel.
inspector.nodePreview.selectNodeLabel=Click to select this node in the Inspector
# LOCALIZATION NOTE (inspector.nodePreview.highlightNodeLabel):
# This string is displayed in a tooltip that is shown when hovering over a the
# inspector icon displayed next to a DOM node preview (e.g. next to something
# like "div#foo.bar").
# DOM node previews can be displayed in places like the animation-inspector, the
# console or the object inspector.
# The tooltip invites the user to click on the icon in order to highlight the
# node in the page.
inspector.nodePreview.highlightNodeLabel=Click to highlight this node in the page

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

@ -43,7 +43,6 @@
label="&performanceUI.enableMemory;"
tooltiptext="&performanceUI.enableMemory.tooltiptext;"/>
<menuitem id="option-enable-allocations"
class="experimental-option"
type="checkbox"
data-pref="enable-allocations"
label="&performanceUI.enableAllocations;"

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

@ -126,14 +126,12 @@ body.theme-sidebar {
#main > p {
position: absolute;
pointer-events: none;
}
#main > p {
margin: 0;
text-align: center;
}
#main > p > span {
#main > p > span,
#main > p > input {
vertical-align: middle;
pointer-events: auto;
}

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

@ -113,6 +113,6 @@ function* testNaviatingHistoryInUI(hud) {
// restores this.
for (let i = INPUT_HISTORY_COUNT - 1; i >= 0; i--) {
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, i, "Pressing up restores last input");
is(jsterm.getInputValue(), i, "Pressing up restores last input");
}
}

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

@ -71,23 +71,23 @@ function consoleOpened(HUD) {
WebConsoleUtils.usageCount = 0;
updateEditUIVisibility();
let oldVal = jsterm.inputNode.value;
let oldVal = jsterm.getInputValue();
goDoCommand("cmd_paste");
let notificationbox = jsterm.hud.document.getElementById("webconsole-notificationbox");
let notification = notificationbox.getNotificationWithValue("selfxss-notification");
ok(notification, "Self-xss notification shown");
is(oldVal, jsterm.inputNode.value, "Paste blocked by self-xss prevention");
is(oldVal, jsterm.getInputValue(), "Paste blocked by self-xss prevention");
// Allow pasting
jsterm.inputNode.value = "allow pasting";
jsterm.setInputValue("allow pasting");
let evt = document.createEvent("KeyboardEvent");
evt.initKeyEvent("keyup", true, true, window,
0, 0, 0, 0,
0, " ".charCodeAt(0));
jsterm.inputNode.dispatchEvent(evt);
jsterm.inputNode.value = "";
jsterm.setInputValue("");
goDoCommand("cmd_paste");
isnot("", jsterm.inputNode.value, "Paste works");
isnot("", jsterm.getInputValue(), "Paste works");
}
function onClipboardPaste() {
ok(!jsterm.completeNode.value, "no completion value after paste");

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

@ -88,7 +88,7 @@ var consoleOpened = Task.async(function*(aHud) {
"Index of the first item from bottom is selected.");
EventUtils.synthesizeKey("VK_DOWN", {});
let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
is(popup.selectedIndex, 0, "index 0 is selected");
is(popup.selectedItem.label, "watch", "watch is selected");
@ -149,7 +149,7 @@ function popupHideAfterTab() {
// At this point the completion suggestion should be accepted.
ok(!popup.isOpen, "popup is not open");
is(inputNode.value, "window.foobarBug585991.watch",
is(jsterm.getInputValue(), "window.foobarBug585991.watch",
"completion was successful after VK_TAB");
ok(!completeNode.value, "completeNode is empty");
@ -164,7 +164,7 @@ function popupHideAfterTab() {
is(popup.selectedIndex, 18, "First index from bottom is selected");
EventUtils.synthesizeKey("VK_DOWN", {});
let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
is(popup.selectedIndex, 0, "index 0 is selected");
is(popup.selectedItem.label, "watch", "watch is selected");
@ -176,7 +176,7 @@ function popupHideAfterTab() {
ok(!popup.isOpen, "popup is not open after VK_ESCAPE");
is(inputNode.value, "window.foobarBug585991.",
is(jsterm.getInputValue(), "window.foobarBug585991.",
"completion was cancelled");
ok(!completeNode.value, "completeNode is empty");
@ -212,7 +212,7 @@ function testReturnKey() {
is(popup.selectedIndex, 18, "First index from bottom is selected");
EventUtils.synthesizeKey("VK_DOWN", {});
let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
let prefix = jsterm.getInputValue().replace(/[\S]/g, " ");
is(popup.selectedIndex, 0, "index 0 is selected");
is(popup.selectedItem.label, "watch", "watch is selected");
@ -231,7 +231,7 @@ function testReturnKey() {
ok(!popup.isOpen, "popup is not open after VK_RETURN");
is(inputNode.value, "window.foobarBug585991.valueOf",
is(jsterm.getInputValue(), "window.foobarBug585991.valueOf",
"completion was successful after VK_RETURN");
ok(!completeNode.value, "completeNode is empty");
@ -324,7 +324,7 @@ function testReturnWithNoSelection() {
function popupHideAfterReturnWithNoSelection() {
ok(!popup.isOpen, "popup is not open after VK_RETURN");
is(inputNode.value, "", "inputNode is empty after VK_RETURN");
is(jsterm.getInputValue(), "", "inputNode is empty after VK_RETURN");
is(completeNode.value, "", "completeNode is empty");
is(jsterm.history[jsterm.history.length - 1], "window.testBug",
"jsterm history is correct");
@ -369,7 +369,7 @@ function testCompletionInText() {
function popupHideAfterCompletionInText() {
// At this point the completion suggestion should be accepted.
ok(!popup.isOpen, "popup is not open");
is(inputNode.value, "dump(window.testBug873250b)",
is(jsterm.getInputValue(), "dump(window.testBug873250b)",
"completion was successful after VK_TAB");
is(inputNode.selectionStart, 26, "cursor location is correct");
is(inputNode.selectionStart, inputNode.selectionEnd,

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

@ -10,7 +10,7 @@
"use strict";
var inputNode, values;
var jsterm, inputNode, values;
var TEST_URI = "data:text/html;charset=utf-8,Web Console test for " +
"bug 594497 and bug 619598";
@ -23,31 +23,33 @@ add_task(function* () {
setup(hud);
performTests();
inputNode = values = null;
jsterm = inputNode = values = null;
});
function setup(HUD) {
inputNode = HUD.jsterm.inputNode;
jsterm = HUD.jsterm;
inputNode = jsterm.inputNode;
inputNode.focus();
ok(!inputNode.value, "inputNode.value is empty");
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");
values = ["document", "window", "document.body"];
values.push(values.join(";\n"), "document.location");
// Execute each of the values;
for (let i = 0; i < values.length; i++) {
HUD.jsterm.setInputValue(values[i]);
HUD.jsterm.execute();
jsterm.setInputValue(values[i]);
jsterm.execute();
}
}
function performTests() {
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, values[4],
"VK_UP: inputNode.value #4 is correct");
is(jsterm.getInputValue(), values[4],
"VK_UP: jsterm.getInputValue() #4 is correct");
ok(inputNode.selectionStart == values[4].length &&
inputNode.selectionStart == inputNode.selectionEnd,
@ -55,8 +57,8 @@ function performTests() {
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, values[3],
"VK_UP: inputNode.value #3 is correct");
is(jsterm.getInputValue(), values[3],
"VK_UP: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart == values[3].length &&
inputNode.selectionStart == inputNode.selectionEnd,
@ -67,17 +69,17 @@ function performTests() {
EventUtils.synthesizeKey("VK_UP", {});
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, values[3],
"VK_UP two times: inputNode.value #3 is correct");
is(jsterm.getInputValue(), values[3],
"VK_UP two times: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart == inputNode.value.indexOf("\n") &&
ok(inputNode.selectionStart == jsterm.getInputValue().indexOf("\n") &&
inputNode.selectionStart == inputNode.selectionEnd,
"caret location is correct");
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, values[3],
"VK_UP again: inputNode.value #3 is correct");
is(jsterm.getInputValue(), values[3],
"VK_UP again: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart == 0 &&
inputNode.selectionStart == inputNode.selectionEnd,
@ -85,18 +87,18 @@ function performTests() {
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, values[2],
"VK_UP: inputNode.value #2 is correct");
is(jsterm.getInputValue(), values[2],
"VK_UP: jsterm.getInputValue() #2 is correct");
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, values[1],
"VK_UP: inputNode.value #1 is correct");
is(jsterm.getInputValue(), values[1],
"VK_UP: jsterm.getInputValue() #1 is correct");
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, values[0],
"VK_UP: inputNode.value #0 is correct");
is(jsterm.getInputValue(), values[0],
"VK_UP: jsterm.getInputValue() #0 is correct");
ok(inputNode.selectionStart == values[0].length &&
inputNode.selectionStart == inputNode.selectionEnd,
@ -104,8 +106,8 @@ function performTests() {
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, values[1],
"VK_DOWN: inputNode.value #1 is correct");
is(jsterm.getInputValue(), values[1],
"VK_DOWN: jsterm.getInputValue() #1 is correct");
ok(inputNode.selectionStart == values[1].length &&
inputNode.selectionStart == inputNode.selectionEnd,
@ -113,13 +115,13 @@ function performTests() {
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, values[2],
"VK_DOWN: inputNode.value #2 is correct");
is(jsterm.getInputValue(), values[2],
"VK_DOWN: jsterm.getInputValue() #2 is correct");
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, values[3],
"VK_DOWN: inputNode.value #3 is correct");
is(jsterm.getInputValue(), values[3],
"VK_DOWN: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart == values[3].length &&
inputNode.selectionStart == inputNode.selectionEnd,
@ -130,17 +132,17 @@ function performTests() {
EventUtils.synthesizeKey("VK_DOWN", {});
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, values[3],
"VK_DOWN two times: inputNode.value #3 is correct");
is(jsterm.getInputValue(), values[3],
"VK_DOWN two times: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart > inputNode.value.lastIndexOf("\n") &&
ok(inputNode.selectionStart > jsterm.getInputValue().lastIndexOf("\n") &&
inputNode.selectionStart == inputNode.selectionEnd,
"caret location is correct");
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, values[3],
"VK_DOWN again: inputNode.value #3 is correct");
is(jsterm.getInputValue(), values[3],
"VK_DOWN again: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart == values[3].length &&
inputNode.selectionStart == inputNode.selectionEnd,
@ -148,11 +150,11 @@ function performTests() {
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, values[4],
"VK_DOWN: inputNode.value #4 is correct");
is(jsterm.getInputValue(), values[4],
"VK_DOWN: jsterm.getInputValue() #4 is correct");
EventUtils.synthesizeKey("VK_DOWN", {});
ok(!inputNode.value,
"VK_DOWN: inputNode.value is empty");
ok(!jsterm.getInputValue(),
"VK_DOWN: jsterm.getInputValue() is empty");
}

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

@ -20,7 +20,7 @@ add_task(function* () {
// Test select all with Control + A.
EventUtils.synthesizeKey("a", { ctrlKey: true });
let inputLength = inputNode.selectionEnd - inputNode.selectionStart;
is(inputLength, inputNode.value.length, "Select all of input");
is(inputLength, jsterm.getInputValue().length, "Select all of input");
// Test do nothing on Control + E.
jsterm.setInputValue("Ignore These Four Words");

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

@ -31,7 +31,7 @@ add_task(function* () {
function doTests(HUD) {
jsterm = HUD.jsterm;
inputNode = jsterm.inputNode;
ok(!jsterm.inputNode.value, "inputNode.value is empty");
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");
is(jsterm.inputNode.selectionStart, 0);
is(jsterm.inputNode.selectionEnd, 0);
@ -96,10 +96,10 @@ function testMultiLineInputNavNoHistory() {
jsterm.setInputValue("");
// simulate shift-return
for (let i = 0; i < lineValues.length; i++) {
jsterm.setInputValue(inputNode.value + lineValues[i]);
jsterm.setInputValue(jsterm.getInputValue() + lineValues[i]);
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
}
let inputValue = inputNode.value;
let inputValue = jsterm.getInputValue();
is(inputNode.selectionStart, inputNode.selectionEnd);
is(inputNode.selectionStart, inputValue.length,
"caret at end of multiline input");
@ -111,36 +111,36 @@ function testMultiLineInputNavNoHistory() {
// Ok, test navigating within the multi-line string!
EventUtils.synthesizeKey("VK_UP", {});
let expectedStringAfterCarat = lineValues[5] + newlineString;
is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
is(jsterm.getInputValue().slice(inputNode.selectionStart), expectedStringAfterCarat,
"up arrow from end of multiline");
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value.slice(inputNode.selectionStart), "",
is(jsterm.getInputValue().slice(inputNode.selectionStart), "",
"down arrow from within multiline");
// navigate up through input lines
EventUtils.synthesizeKey("p", { ctrlKey: true });
is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
is(jsterm.getInputValue().slice(inputNode.selectionStart), expectedStringAfterCarat,
"ctrl-p from end of multiline");
for (let i = 4; i >= 0; i--) {
EventUtils.synthesizeKey("p", { ctrlKey: true });
expectedStringAfterCarat = lineValues[i] + newlineString +
expectedStringAfterCarat;
is(inputNode.value.slice(inputNode.selectionStart),
is(jsterm.getInputValue().slice(inputNode.selectionStart),
expectedStringAfterCarat, "ctrl-p from within line " + i +
" of multiline input");
}
EventUtils.synthesizeKey("p", { ctrlKey: true });
is(inputNode.selectionStart, 0, "reached start of input");
is(inputNode.value, inputValue,
is(jsterm.getInputValue(), inputValue,
"no change to multiline input on ctrl-p from beginning of multiline");
// navigate to end of first line
EventUtils.synthesizeKey("e", { ctrlKey: true });
let caretPos = inputNode.selectionStart;
let expectedStringBeforeCarat = lineValues[0];
is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
is(jsterm.getInputValue().slice(0, caretPos), expectedStringBeforeCarat,
"ctrl-e into multiline input");
EventUtils.synthesizeKey("e", { ctrlKey: true });
is(inputNode.selectionStart, caretPos,
@ -152,13 +152,13 @@ function testMultiLineInputNavNoHistory() {
EventUtils.synthesizeKey("a", { ctrlKey: true });
caretPos = inputNode.selectionStart;
expectedStringBeforeCarat += newlineString;
is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
is(jsterm.getInputValue().slice(0, caretPos), expectedStringBeforeCarat,
"ctrl-a to beginning of line " + (i + 1) + " in multiline input");
EventUtils.synthesizeKey("e", { ctrlKey: true });
caretPos = inputNode.selectionStart;
expectedStringBeforeCarat += lineValues[i];
is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
is(jsterm.getInputValue().slice(0, caretPos), expectedStringBeforeCarat,
"ctrl-e to end of line " + (i + 1) + "in multiline input");
}
}
@ -195,27 +195,27 @@ function testNavWithHistory() {
// single-line inputs will update from history from end of line
EventUtils.synthesizeKey("p", { ctrlKey: true });
}
is(inputNode.value, values[i - 1],
is(jsterm.getInputValue(), values[i - 1],
"ctrl-p updates inputNode from backwards history values[" + i - 1 + "]");
}
let inputValue = inputNode.value;
let inputValue = jsterm.getInputValue();
EventUtils.synthesizeKey("p", { ctrlKey: true });
is(inputNode.selectionStart, 0,
"ctrl-p at beginning of history moves caret location to beginning " +
"of line");
is(inputNode.value, inputValue,
is(jsterm.getInputValue(), inputValue,
"no change to input value on ctrl-p from beginning of line");
// Navigate forwards history with ctrl-n
for (let i = 1; i < values.length; i++) {
EventUtils.synthesizeKey("n", { ctrlKey: true });
is(inputNode.value, values[i],
is(jsterm.getInputValue(), values[i],
"ctrl-n updates inputNode from forwards history values[" + i + "]");
is(inputNode.selectionStart, values[i].length,
"caret location correct at end of history input for values[" + i + "]");
}
EventUtils.synthesizeKey("n", { ctrlKey: true });
ok(!inputNode.value, "ctrl-n at end of history updates to empty input");
ok(!jsterm.getInputValue(), "ctrl-n at end of history updates to empty input");
// Simulate editing multi-line
inputValue = "one\nlinebreak";
@ -223,11 +223,11 @@ function testNavWithHistory() {
// Attempt nav within input
EventUtils.synthesizeKey("p", { ctrlKey: true });
is(inputNode.value, inputValue,
is(jsterm.getInputValue(), inputValue,
"ctrl-p from end of multi-line does not trigger history");
EventUtils.synthesizeKey("a", { ctrlKey: true });
EventUtils.synthesizeKey("p", { ctrlKey: true });
is(inputNode.value, values[values.length - 1],
is(jsterm.getInputValue(), values[values.length - 1],
"ctrl-p from start of multi-line triggers history");
}

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

@ -28,36 +28,36 @@ add_task(function* () {
function testEditedInputHistory(HUD) {
let jsterm = HUD.jsterm;
let inputNode = jsterm.inputNode;
ok(!inputNode.value, "inputNode.value is empty");
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");
is(inputNode.selectionStart, 0);
is(inputNode.selectionEnd, 0);
jsterm.setInputValue('"first item"');
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, '"first item"', "null test history up");
is(jsterm.getInputValue(), '"first item"', "null test history up");
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, '"first item"', "null test history down");
is(jsterm.getInputValue(), '"first item"', "null test history down");
jsterm.execute();
is(inputNode.value, "", "cleared input line after submit");
is(jsterm.getInputValue(), "", "cleared input line after submit");
jsterm.setInputValue('"editing input 1"');
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, '"first item"', "test history up");
is(jsterm.getInputValue(), '"first item"', "test history up");
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, '"editing input 1"',
is(jsterm.getInputValue(), '"editing input 1"',
"test history down restores in-progress input");
jsterm.setInputValue('"second item"');
jsterm.execute();
jsterm.setInputValue('"editing input 2"');
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, '"second item"', "test history up");
is(jsterm.getInputValue(), '"second item"', "test history up");
EventUtils.synthesizeKey("VK_UP", {});
is(inputNode.value, '"first item"', "test history up");
is(jsterm.getInputValue(), '"first item"', "test history up");
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, '"second item"', "test history down");
is(jsterm.getInputValue(), '"second item"', "test history down");
EventUtils.synthesizeKey("VK_DOWN", {});
is(inputNode.value, '"editing input 2"',
is(jsterm.getInputValue(), '"editing input 2"',
"test history down restores new in-progress input again");
}

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

@ -57,7 +57,7 @@ add_task(function*() {
info("Waiting for input to be set");
yield onceInputSet;
is(hud.jsterm.inputNode.value, "temp0", "Input was set");
is(hud.jsterm.getInputValue(), "temp0", "Input was set");
let executedResult = yield hud.jsterm.execute();
ok(executedResult.textContent.includes("{ baz: 1 }"),

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

@ -3252,7 +3252,7 @@ JSTerm.prototype = {
*
* @param string [executeString]
* The string you want to execute. If this is not provided, the current
* user input is used - taken from |this.inputNode.value|.
* user input is used - taken from |this.getInputValue()|.
* @param function [callback]
* Optional function to invoke when the result is displayed.
* This is deprecated - please use the promise return value instead.
@ -3270,7 +3270,7 @@ JSTerm.prototype = {
}
// attempt to execute the content of the inputNode
executeString = executeString || this.inputNode.value;
executeString = executeString || this.getInputValue();
if (!executeString) {
return;
}
@ -3863,16 +3863,25 @@ JSTerm.prototype = {
this.emit("set-input-value");
},
/**
* Gets the value from the input field
* @returns string
*/
getInputValue: function()
{
return this.inputNode.value || "";
},
/**
* The inputNode "input" and "keyup" event handler.
* @private
*/
_inputEventHandler: function JST__inputEventHandler()
{
if (this.lastInputValue != this.inputNode.value) {
if (this.lastInputValue != this.getInputValue()) {
this.resizeInput();
this.complete(this.COMPLETE_HINT_ONLY);
this.lastInputValue = this.inputNode.value;
this.lastInputValue = this.getInputValue();
this._inputChanged = true;
}
},
@ -3897,6 +3906,7 @@ JSTerm.prototype = {
_keyPress: function JST__keyPress(event)
{
let inputNode = this.inputNode;
let inputValue = this.getInputValue();
let inputUpdated = false;
if (event.ctrlKey) {
@ -3906,12 +3916,12 @@ JSTerm.prototype = {
if (Services.appinfo.OS == "WINNT") {
break;
}
let lineEndPos = inputNode.value.length;
let lineEndPos = inputValue.length;
if (this.hasMultilineInput()) {
// find index of closest newline >= cursor
for (let i = inputNode.selectionEnd; i<lineEndPos; i++) {
if (inputNode.value.charAt(i) == "\r" ||
inputNode.value.charAt(i) == "\n") {
if (inputValue.charAt(i) == "\r" ||
inputValue.charAt(i) == "\n") {
lineEndPos = i;
break;
}
@ -4060,7 +4070,7 @@ JSTerm.prototype = {
if (this.autocompletePopup.isOpen) {
this.autocompletePopup.selectedIndex = 0;
event.preventDefault();
} else if (this.inputNode.value.length <= 0) {
} else if (inputValue.length <= 0) {
this.hud.outputNode.parentNode.scrollTop = 0;
event.preventDefault();
}
@ -4070,7 +4080,7 @@ JSTerm.prototype = {
if (this.autocompletePopup.isOpen) {
this.autocompletePopup.selectedIndex = this.autocompletePopup.itemCount - 1;
event.preventDefault();
} else if (this.inputNode.value.length <= 0) {
} else if (inputValue.length <= 0) {
this.hud.outputNode.parentNode.scrollTop = this.hud.outputNode.parentNode.scrollHeight;
event.preventDefault();
}
@ -4086,7 +4096,7 @@ JSTerm.prototype = {
let cursorAtTheEnd = this.inputNode.selectionStart ==
this.inputNode.selectionEnd &&
this.inputNode.selectionStart ==
this.inputNode.value.length;
inputValue.length;
let haveSuggestion = this.autocompletePopup.isOpen ||
this.lastCompletion.value;
let useCompletion = cursorAtTheEnd || this._autocompletePopupNavigated;
@ -4154,7 +4164,7 @@ JSTerm.prototype = {
// Note: this code does not store changes to items that are already in
// history.
if (this.historyPlaceHolder+1 == this.historyIndex) {
this.history[this.historyIndex] = this.inputNode.value || "";
this.history[this.historyIndex] = this.getInputValue() || "";
}
this.setInputValue(inputVal);
@ -4183,7 +4193,7 @@ JSTerm.prototype = {
*/
hasMultilineInput: function JST_hasMultilineInput()
{
return /[\r\n]/.test(this.inputNode.value);
return /[\r\n]/.test(this.getInputValue());
},
/**
@ -4253,7 +4263,7 @@ JSTerm.prototype = {
* completion and the input value stayed the same compared to the
* last time this function was called, then the same completion is
* used again. If there is only one possible completion, then
* the inputNode.value is set to this value and the selection is set
* the this.getInputValue() is set to this value and the selection is set
* from the current cursor position to the end of the completed text.
* @param function callback
* Optional function invoked when the autocomplete properties are
@ -4264,7 +4274,7 @@ JSTerm.prototype = {
complete: function JSTF_complete(type, callback)
{
let inputNode = this.inputNode;
let inputValue = inputNode.value;
let inputValue = this.getInputValue();
let frameActor = this.getFrameActor(this.SELECTED_FRAME);
// If the inputNode has no value, then don't try to complete on it.
@ -4328,13 +4338,14 @@ JSTerm.prototype = {
function JST__updateCompletionResult(type, callback)
{
let frameActor = this.getFrameActor(this.SELECTED_FRAME);
if (this.lastCompletion.value == this.inputNode.value && frameActor == this._lastFrameActorId) {
if (this.lastCompletion.value == this.getInputValue() &&
frameActor == this._lastFrameActorId) {
return;
}
let requestId = gSequenceId();
let cursor = this.inputNode.selectionStart;
let input = this.inputNode.value.substring(0, cursor);
let input = this.getInputValue().substring(0, cursor);
let cache = this._autocompleteCache;
// If the current input starts with the previous input, then we already
@ -4404,7 +4415,7 @@ JSTerm.prototype = {
function JST__receiveAutocompleteProperties(requestId, callback, message)
{
let inputNode = this.inputNode;
let inputValue = inputNode.value;
let inputValue = this.getInputValue();
if (this.lastCompletion.value == inputValue ||
requestId != this.lastCompletion.requestId) {
return;
@ -4441,7 +4452,7 @@ JSTerm.prototype = {
};
if (items.length > 1 && !popup.isOpen) {
let str = this.inputNode.value.substr(0, this.inputNode.selectionStart);
let str = this.getInputValue().substr(0, this.inputNode.selectionStart);
let offset = str.length - (str.lastIndexOf("\n") + 1) - lastPart.length;
let x = offset * this.hud._inputCharWidth;
popup.openPopup(inputNode, x + this.hud._chevronWidth);
@ -4475,7 +4486,7 @@ JSTerm.prototype = {
onAutocompleteSelect: function JSTF_onAutocompleteSelect()
{
// Render the suggestion only if the cursor is at the end of the input.
if (this.inputNode.selectionStart != this.inputNode.value.length) {
if (this.inputNode.selectionStart != this.getInputValue().length) {
return;
}
@ -4521,7 +4532,7 @@ JSTerm.prototype = {
let suffix = currentItem.label.substring(this.lastCompletion.
matchProp.length);
let cursor = this.inputNode.selectionStart;
let value = this.inputNode.value;
let value = this.getInputValue();
this.setInputValue(value.substr(0, cursor) + suffix + value.substr(cursor));
let newCursor = cursor + suffix.length;
this.inputNode.selectionStart = this.inputNode.selectionEnd = newCursor;
@ -4542,7 +4553,7 @@ JSTerm.prototype = {
updateCompleteNode: function JSTF_updateCompleteNode(suffix)
{
// completion prefix = input, with non-control chars replaced by spaces
let prefix = suffix ? this.inputNode.value.replace(/[\S]/g, " ") : "";
let prefix = suffix ? this.getInputValue().replace(/[\S]/g, " ") : "";
this.completeNode.value = prefix + suffix;
},

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

@ -70,6 +70,7 @@ var AnimationPlayerActor = ActorClass({
this.onAnimationMutation = this.onAnimationMutation.bind(this);
this.walker = animationsActor.walker;
this.tabActor = animationsActor.tabActor;
this.player = player;
this.node = player.effect.target;
@ -89,7 +90,9 @@ var AnimationPlayerActor = ActorClass({
if (this.observer && !Cu.isDeadWrapper(this.observer)) {
this.observer.disconnect();
}
this.tabActor = this.player = this.node = this.styles = this.observer = null;
this.tabActor = this.player = this.node = this.styles = null;
this.observer = this.walker = null;
Actor.prototype.destroy.call(this);
},
@ -107,6 +110,12 @@ var AnimationPlayerActor = ActorClass({
let data = this.getCurrentState();
data.actor = this.actorID;
// If we know the WalkerActor, and if the animated node is known by it, then
// return its corresponding NodeActor ID too.
if (this.walker && this.walker.hasNode(this.node)) {
data.animationTargetNodeActorID = this.walker.getNode(this.node).actorID;
}
return data;
},
@ -381,6 +390,18 @@ var AnimationPlayerFront = FrontClass(AnimationPlayerActor, {
Front.prototype.destroy.call(this);
},
/**
* If the AnimationsActor was given a reference to the WalkerActor previously
* then calling this getter will return the animation target NodeFront.
*/
get animationTargetNodeFront() {
if (!this._form.animationTargetNodeActorID) {
return null;
}
return this.conn.getActor(this._form.animationTargetNodeActorID);
},
/**
* Getter for the initial state of the player. Up to date states can be
* retrieved by calling the getCurrentState method.
@ -495,7 +516,7 @@ var AnimationsActor = exports.AnimationsActor = ActorClass({
events.off(this.tabActor, "navigate", this.onNavigate);
this.stopAnimationPlayerUpdates();
this.tabActor = this.observer = this.actors = null;
this.tabActor = this.observer = this.actors = this.walker = null;
},
/**
@ -506,6 +527,23 @@ var AnimationsActor = exports.AnimationsActor = ActorClass({
this.destroy();
},
/**
* Clients can optionally call this with a reference to their WalkerActor.
* If they do, then AnimationPlayerActor's forms are going to also include
* NodeActor IDs when the corresponding NodeActors do exist.
* This, in turns, is helpful for clients to avoid having to go back once more
* to the server to get a NodeActor for a particular animation.
* @param {WalkerActor} walker
*/
setWalkerActor: method(function(walker) {
this.walker = walker;
}, {
request: {
walker: Arg(0, "domwalker")
},
response: {}
}),
/**
* Retrieve the list of AnimationPlayerActor actors for currently running
* animations on a node and its descendants.

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

@ -1367,7 +1367,7 @@ var WalkerActor = protocol.ActorClass({
let target = current.target;
if (this._refMap.has(target)) {
let actor = this._refMap.get(target);
let actor = this.getNode(target);
let mutation = {
type: "events",
target: actor.actorID,
@ -1469,13 +1469,30 @@ var WalkerActor = protocol.ActorClass({
protocol.Actor.prototype.unmanage.call(this, actor);
},
hasNode: function(node) {
return this._refMap.has(node);
/**
* Determine if the walker has come across this DOM node before.
* @param {DOMNode} rawNode
* @return {Boolean}
*/
hasNode: function(rawNode) {
return this._refMap.has(rawNode);
},
/**
* If the walker has come across this DOM node before, then get the
* corresponding node actor.
* @param {DOMNode} rawNode
* @return {NodeActor}
*/
getNode: function(rawNode) {
return this._refMap.get(rawNode);
},
_ref: function(node) {
let actor = this._refMap.get(node);
if (actor) return actor;
let actor = this.getNode(node);
if (actor) {
return actor;
}
actor = new NodeActor(this, node);
@ -1763,7 +1780,7 @@ var WalkerActor = protocol.ActorClass({
let child = walker.firstChild();
while (child) {
let childActor = this._refMap.get(child);
let childActor = this.getNode(child);
if (childActor) {
this.releaseNode(childActor, options);
}
@ -1789,7 +1806,7 @@ var WalkerActor = protocol.ActorClass({
let walker = this.getDocumentWalker(node.rawNode);
let cur;
while ((cur = walker.parentNode())) {
let parent = this._refMap.get(cur);
let parent = this.getNode(cur);
if (!parent) {
// This parent didn't exist, so hasn't been seen by the client yet.
newParents.add(this._ref(cur));
@ -2942,7 +2959,7 @@ var WalkerActor = protocol.ActorClass({
events.emit(this, "any-mutation");
for (let change of mutations) {
let targetActor = this._refMap.get(change.target);
let targetActor = this.getNode(change.target);
if (!targetActor) {
continue;
}
@ -2972,7 +2989,7 @@ var WalkerActor = protocol.ActorClass({
let removedActors = [];
let addedActors = [];
for (let removed of change.removedNodes) {
let removedActor = this._refMap.get(removed);
let removedActor = this.getNode(removed);
if (!removedActor) {
// If the client never encountered this actor we don't need to
// mention that it was removed.
@ -2983,7 +3000,7 @@ var WalkerActor = protocol.ActorClass({
removedActors.push(removedActor.actorID);
}
for (let added of change.addedNodes) {
let addedActor = this._refMap.get(added);
let addedActor = this.getNode(added);
if (!addedActor) {
// If the client never encounted this actor we don't need to tell
// it about its addition for ownership tree purposes - if the
@ -3021,7 +3038,7 @@ var WalkerActor = protocol.ActorClass({
return;
}
let frame = getFrameElement(window);
let frameActor = this._refMap.get(frame);
let frameActor = this.getNode(frame);
if (!frameActor) {
return;
}
@ -3076,7 +3093,7 @@ var WalkerActor = protocol.ActorClass({
}
let doc = window.document;
let documentActor = this._refMap.get(doc);
let documentActor = this.getNode(doc);
if (!documentActor) {
return;
}
@ -3098,7 +3115,7 @@ var WalkerActor = protocol.ActorClass({
// they should reread the children list.
this.queueMutation({
type: "childList",
target: this._refMap.get(parentNode).actorID,
target: this.getNode(parentNode).actorID,
added: [],
removed: []
});

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

@ -4,7 +4,7 @@
"use strict";
const {Cc, Ci, Cu} = require("chrome");
const {Cc, Ci} = require("chrome");
const promise = require("promise");
const protocol = require("devtools/server/protocol");
const {Arg, Option, method, RetVal, types} = protocol;
@ -572,7 +572,8 @@ var PageStyleActor = protocol.ActorClass({
this.cssLogic.highlight(node.rawNode);
let entries = [];
entries = entries.concat(this._getAllElementRules(node, undefined, options));
entries = entries.concat(this._getAllElementRules(node, undefined,
options));
let result = this.getAppliedProps(node, entries, options);
for (let rule of result.rules) {
@ -611,7 +612,8 @@ var PageStyleActor = protocol.ActorClass({
* - pseudoElement String
*/
_getAllElementRules: function(node, inherited, options) {
let {bindingElement, pseudo} = CssLogic.getBindingElementAndPseudo(node.rawNode);
let {bindingElement, pseudo} =
CssLogic.getBindingElementAndPseudo(node.rawNode);
let rules = [];
if (!bindingElement || !bindingElement.style) {
@ -644,21 +646,24 @@ var PageStyleActor = protocol.ActorClass({
// Add normal rules. Typically this is passing in the node passed into the
// function, unless if that node was ::before/::after. In which case,
// it will pass in the parentNode along with "::before"/"::after".
this._getElementRules(bindingElement, pseudo, inherited, options).forEach(rule => {
// The only case when there would be a pseudo here is ::before/::after,
// and in this case we want to tell the view that it belongs to the
// element (which is a _moz_generated_content native anonymous element).
rule.pseudoElement = null;
rules.push(rule);
});
this._getElementRules(bindingElement, pseudo, inherited, options)
.forEach(oneRule => {
// The only case when there would be a pseudo here is
// ::before/::after, and in this case we want to tell the
// view that it belongs to the element (which is a
// _moz_generated_content native anonymous element).
oneRule.pseudoElement = null;
rules.push(oneRule);
});
// Now any pseudos (except for ::before / ::after, which was handled as
// a 'normal rule' above.
if (showElementStyles) {
for (let pseudo of PSEUDO_ELEMENTS_TO_READ) {
this._getElementRules(bindingElement, pseudo, inherited, options).forEach(rule => {
rules.push(rule);
});
for (let readPseudo of PSEUDO_ELEMENTS_TO_READ) {
this._getElementRules(bindingElement, readPseudo, inherited, options)
.forEach(oneRule => {
rules.push(oneRule);
});
}
}
@ -741,7 +746,8 @@ var PageStyleActor = protocol.ActorClass({
if (options.inherited) {
let parent = this.walker.parentNode(node);
while (parent && parent.rawNode.nodeType != Ci.nsIDOMNode.DOCUMENT_NODE) {
entries = entries.concat(this._getAllElementRules(parent, parent, options));
entries = entries.concat(this._getAllElementRules(parent, parent,
options));
parent = this.walker.parentNode(parent);
}
}
@ -756,10 +762,12 @@ var PageStyleActor = protocol.ActorClass({
let selectors = CssLogic.getSelectors(domRule);
let element = entry.inherited ? entry.inherited.rawNode : node.rawNode;
let {bindingElement, pseudo} = CssLogic.getBindingElementAndPseudo(element);
let {bindingElement, pseudo} =
CssLogic.getBindingElementAndPseudo(element);
entry.matchedSelectors = [];
for (let i = 0; i < selectors.length; i++) {
if (DOMUtils.selectorMatchesElement(bindingElement, domRule, i, pseudo)) {
if (DOMUtils.selectorMatchesElement(bindingElement, domRule, i,
pseudo)) {
entry.matchedSelectors.push(selectors[i]);
}
}
@ -1005,9 +1013,9 @@ var PageStyleActor = protocol.ActorClass({
exports.PageStyleActor = PageStyleActor;
/**
* Front object for the PageStyleActor
* PageStyleFront, the front object for the PageStyleActor
*/
var PageStyleFront = protocol.FrontClass(PageStyleActor, {
protocol.FrontClass(PageStyleActor, {
initialize: function(conn, form, ctx, detail) {
protocol.Front.prototype.initialize.call(this, conn, form, ctx, detail);
this.inspector = this.parent();
@ -1041,7 +1049,7 @@ var PageStyleFront = protocol.FrontClass(PageStyleActor, {
impl: "_getMatchedSelectors"
}),
getApplied: protocol.custom(Task.async(function*(node, options={}) {
getApplied: protocol.custom(Task.async(function*(node, options = {}) {
// If the getApplied method doesn't recreate the style cache itself, this
// means a call to cssLogic.highlight is required before trying to access
// the applied rules. Issue a request to getLayout if this is the case.
@ -1126,7 +1134,7 @@ var StyleRuleActor = protocol.ActorClass({
return this.pageStyle.conn;
},
destroy: function () {
destroy: function() {
if (!this.rawStyle) {
return;
}
@ -1175,7 +1183,7 @@ var StyleRuleActor = protocol.ActorClass({
},
toString: function() {
return "[StyleRuleActor for " + this.rawRule + "]"
return "[StyleRuleActor for " + this.rawRule + "]";
},
form: function(detail) {
@ -1199,7 +1207,8 @@ var StyleRuleActor = protocol.ActorClass({
};
if (this.rawRule.parentRule) {
form.parentRule = this.pageStyle._styleRef(this.rawRule.parentRule).actorID;
form.parentRule =
this.pageStyle._styleRef(this.rawRule.parentRule).actorID;
// CSS rules that we call media rules are STYLE_RULES that are children
// of MEDIA_RULEs. We need to check the parentRule to check if a rule is
@ -1213,7 +1222,8 @@ var StyleRuleActor = protocol.ActorClass({
}
}
if (this._parentSheet) {
form.parentStyleSheet = this.pageStyle._sheetRef(this._parentSheet).actorID;
form.parentStyleSheet =
this.pageStyle._sheetRef(this._parentSheet).actorID;
}
// One tricky thing here is that other methods in this actor must
@ -1519,7 +1529,7 @@ var StyleRuleActor = protocol.ActorClass({
parentStyleSheet.insertRule(value + " " + ruleText, i);
parentStyleSheet.deleteRule(i + 1);
break;
} catch(e) {
} catch (e) {
// The selector could be invalid, or the rule could fail to insert.
return null;
}
@ -1550,7 +1560,7 @@ var StyleRuleActor = protocol.ActorClass({
let document = this.getDocument(this._parentSheet);
// Extract the selector, and pseudo elements and classes
let [selector, pseudoProp] = value.split(/(:{1,2}.+$)/);
let [selector] = value.split(/(:{1,2}.+$)/);
let selectorElement;
try {
@ -1625,7 +1635,7 @@ var StyleRuleActor = protocol.ActorClass({
let isMatching = false;
try {
isMatching = node.rawNode.matches(value);
} catch(e) {
} catch (e) {
// This fails when value is an invalid selector.
}
@ -1642,9 +1652,9 @@ var StyleRuleActor = protocol.ActorClass({
});
/**
* Front for the StyleRule actor.
* StyleRuleFront, the front for the StyleRule actor.
*/
var StyleRuleFront = protocol.FrontClass(StyleRuleActor, {
protocol.FrontClass(StyleRuleActor, {
initialize: function(client, form, ctx, detail) {
protocol.Front.prototype.initialize.call(this, client, form, ctx, detail);
},
@ -1910,9 +1920,13 @@ var RuleModificationList = Class({
* generally for setting properties
* on an element's style.
* @param {String} name current name of the property
*
* This parameter is also passed, but as it is not used in this
* implementation, it is omitted. It is documented here as this
* code also defined the interface implemented by @see RuleRewriter.
* @param {String} newName new name of the property
*/
renameProperty: function(index, name, newName) {
renameProperty: function(index, name) {
this.removeProperty(index, name);
},
@ -1940,6 +1954,11 @@ var RuleModificationList = Class({
* Create a new property. This implementation does nothing, because
* |setRuleText| is not available.
*
* These parameter are passed, but as they are not used in this
* implementation, they are omitted. They are documented here as
* this code also defined the interface implemented by @see
* RuleRewriter.
*
* @param {Number} index index of the property in the rule.
* This can be -1 in the case where
* the rule does not support setRuleText;
@ -1950,7 +1969,7 @@ var RuleModificationList = Class({
* @param {String} priority priority of the new property; either
* the empty string or "important"
*/
createProperty: function(index, name, value, priority) {
createProperty: function() {
// Nothing.
},
});

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

@ -1032,6 +1032,9 @@ WebConsoleActor.prototype =
if (key == "NetworkMonitor.saveRequestAndResponseBodies" &&
this.networkMonitor) {
this.networkMonitor.saveRequestAndResponseBodies = this._prefs[key];
if (this.networkMonitorChild) {
this.networkMonitorChild.saveRequestAndResponseBodies = this._prefs[key];
}
}
}
return { updated: Object.keys(aRequest.preferences) };

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

@ -181,6 +181,8 @@ DominatorTreeNode.getLabelAndShallowSize = function (nodeId,
* `maxSiblings` within any single node's children.
*
* @param {DominatorTree} dominatorTree
* @param {HeapSnapshot} snapshot
* @param {Object} breakdown
* @param {Number} maxDepth
* @param {Number} maxSiblings
*
@ -204,7 +206,7 @@ DominatorTreeNode.partialTraversal = function (dominatorTree,
for (let i = 0; i < endIdx; i++) {
DominatorTreeNode.addChild(node, dfs(childNodeIds[i], newDepth));
}
node.moreChildrenAvailable = childNodeIds.length < endIdx;
node.moreChildrenAvailable = endIdx < childNodeIds.length;
} else {
node.moreChildrenAvailable = childNodeIds.length > 0;
}

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

@ -0,0 +1,157 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that we correctly set `moreChildrenAvailable` when doing a partial
// traversal of a dominator tree to create the initial incrementally loaded
// `DominatorTreeNode` tree.
// `tree` maps parent to children:
//
// 100
// |- 200
// | |- 500
// | |- 600
// | `- 700
// |- 300
// | |- 800
// | |- 900
// `- 400
// |- 1000
// |- 1100
// `- 1200
const tree = new Map([
[100, [200, 300, 400]],
[200, [500, 600, 700]],
[300, [800, 900]],
[400, [1000, 1100, 1200]]
]);
const mockDominatorTree = {
root: 100,
getRetainedSize: _ => 10,
getImmediatelyDominated: id => (tree.get(id) || []).slice()
};
const mockSnapshot = {
describeNode: _ => ({
objects: { count: 0, bytes: 0 },
strings: { count: 0, bytes: 0 },
scripts: { count: 0, bytes: 0 },
other: { SomeType: { count: 1, bytes: 10 } }
})
};
const breakdown = {
by: "coarseType",
objects: { by: "count", count: true, bytes: true },
strings: { by: "count", count: true, bytes: true },
scripts: { by: "count", count: true, bytes: true },
other: {
by: "internalType",
then: { by: "count", count: true, bytes: true }
},
};
const expected = {
nodeId: 100,
label: [
"other",
"SomeType"
],
shallowSize: 10,
retainedSize: 10,
children: [
{
nodeId: 200,
label: [
"other",
"SomeType"
],
shallowSize: 10,
retainedSize: 10,
parentId: 100,
children: [
{
nodeId: 500,
label: [
"other",
"SomeType"
],
shallowSize: 10,
retainedSize: 10,
parentId: 200,
moreChildrenAvailable: false,
children: undefined
},
{
nodeId: 600,
label: [
"other",
"SomeType"
],
shallowSize: 10,
retainedSize: 10,
parentId: 200,
moreChildrenAvailable: false,
children: undefined
}
],
moreChildrenAvailable: true
},
{
nodeId: 300,
label: [
"other",
"SomeType"
],
shallowSize: 10,
retainedSize: 10,
parentId: 100,
children: [
{
nodeId: 800,
label: [
"other",
"SomeType"
],
shallowSize: 10,
retainedSize: 10,
parentId: 300,
moreChildrenAvailable: false,
children: undefined
},
{
nodeId: 900,
label: [
"other",
"SomeType"
],
shallowSize: 10,
retainedSize: 10,
parentId: 300,
moreChildrenAvailable: false,
children: undefined
}
],
moreChildrenAvailable: false
}
],
moreChildrenAvailable: true,
parentId: undefined,
};
function run_test() {
// Traverse the whole depth of the test tree, but one short of the number of
// siblings. This will exercise the moreChildrenAvailable handling for
// siblings.
const actual = DominatorTreeNode.partialTraversal(mockDominatorTree,
mockSnapshot,
breakdown,
/* maxDepth = */ 4,
/* siblings = */ 2);
dumpn("Expected = " + JSON.stringify(expected, null, 2));
dumpn("Actual = " + JSON.stringify(actual, null, 2));
assertStructurallyEquivalent(expected, actual);
}

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

@ -0,0 +1,56 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that the retained size of a node is the sum of its children retained
// sizes plus its shallow size.
// Note that we don't assert directly, only if we get an unexpected
// value. There are just way too many nodes in the heap graph to assert for
// every one. This test would constantly time out and assertion messages would
// overflow the log size.
function fastAssert(cond, msg) {
if (!cond) {
ok(false, msg);
}
}
var COUNT = { by: "count", count: false, bytes: true };
function run_test() {
var path = saveNewHeapSnapshot();
var snapshot = ChromeUtils.readHeapSnapshot(path);
var dominatorTree = snapshot.computeDominatorTree();
// Do a traversal of the dominator tree and assert the relationship between
// retained size, shallow size, and children's retained sizes.
var root = dominatorTree.root;
var stack = [root];
while (stack.length > 0) {
var top = stack.pop();
var children = dominatorTree.getImmediatelyDominated(top);
var topRetainedSize = dominatorTree.getRetainedSize(top);
var topShallowSize = snapshot.describeNode(COUNT, top).bytes;
fastAssert(topShallowSize <= topRetainedSize,
"The shallow size should be less than or equal to the " +
"retained size");
var sumOfChildrensRetainedSizes = 0;
for (var i = 0; i < children.length; i++) {
sumOfChildrensRetainedSizes += dominatorTree.getRetainedSize(children[i]);
stack.push(children[i]);
}
fastAssert(sumOfChildrensRetainedSizes <= topRetainedSize,
"The sum of the children's retained sizes should be less than " +
"or equal to the retained size");
fastAssert(sumOfChildrensRetainedSizes + topShallowSize === topRetainedSize,
"The sum of the children's retained sizes plus the shallow " +
"size should be equal to the retained size");
}
ok(true, "Successfully walked the tree");
do_test_finished();
}

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

@ -33,6 +33,7 @@ support-files =
[test_DominatorTree_03.js]
[test_DominatorTree_04.js]
[test_DominatorTree_05.js]
[test_DominatorTree_06.js]
[test_DominatorTreeNode_getNodeByIdAlongPath_01.js]
[test_DominatorTreeNode_insert_01.js]
[test_DominatorTreeNode_insert_02.js]
@ -41,6 +42,7 @@ support-files =
[test_DominatorTreeNode_LabelAndShallowSize_02.js]
[test_DominatorTreeNode_LabelAndShallowSize_03.js]
[test_DominatorTreeNode_LabelAndShallowSize_04.js]
[test_DominatorTreeNode_partialTraversal_01.js]
[test_HeapAnalyses_computeDominatorTree_01.js]
[test_HeapAnalyses_computeDominatorTree_02.js]
[test_HeapAnalyses_deleteHeapSnapshot_01.js]

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

@ -223,8 +223,10 @@ NetworkResponseListener.prototype = {
// In the multi-process mode, the conversion happens on the child side while we can
// only monitor the channel on the parent side. If the content is gzipped, we have
// to unzip it ourself. For that we use the stream converter services.
// Do not do that for Service workers as they are run in the child process.
let channel = this.request;
if (channel instanceof Ci.nsIEncodedChannel &&
if (!this.httpActivity.fromServiceWorker &&
channel instanceof Ci.nsIEncodedChannel &&
channel.contentEncodings &&
!channel.applyConversion) {
let encodingHeader = channel.getResponseHeader("Content-Encoding");
@ -860,6 +862,7 @@ NetworkMonitor.prototype = {
event.startedDateTime = (timestamp ? new Date(Math.round(timestamp / 1000)) : new Date()).toISOString();
event.fromCache = fromCache;
event.fromServiceWorker = fromServiceWorker;
httpActivity.fromServiceWorker = fromServiceWorker;
if (extraStringData) {
event.headersSize = extraStringData.length;

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

@ -228,6 +228,10 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
}
BluetoothA2dpManager::~BluetoothA2dpManager()
{ }
void
BluetoothA2dpManager::Uninit()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
@ -273,9 +277,9 @@ BluetoothA2dpManager::Get()
// If we're in shutdown, don't create a new instance
NS_ENSURE_FALSE(sInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothA2dpManager* manager = new BluetoothA2dpManager();
sBluetoothA2dpManager = manager;
// Create a new instance and return
sBluetoothA2dpManager = new BluetoothA2dpManager();
return sBluetoothA2dpManager;
}
@ -297,6 +301,9 @@ public:
sBtA2dpInterface->SetNotificationHandler(nullptr);
sBtA2dpInterface = nullptr;
sBluetoothA2dpManager->Uninit();
sBluetoothA2dpManager = nullptr;
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
@ -309,6 +316,9 @@ public:
sBtA2dpInterface->SetNotificationHandler(nullptr);
sBtA2dpInterface = nullptr;
sBluetoothA2dpManager->Uninit();
sBluetoothA2dpManager = nullptr;
if (mRes) {
mRes->Deinit();
}

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

@ -58,6 +58,7 @@ private:
BluetoothA2dpManager();
void Uninit();
void HandleShutdown();
void NotifyConnectionStatusChanged();

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

@ -268,6 +268,10 @@ BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
}
BluetoothAvrcpManager::~BluetoothAvrcpManager()
{ }
void
BluetoothAvrcpManager::Uninit()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
@ -294,9 +298,9 @@ BluetoothAvrcpManager::Get()
// If we're in shutdown, don't create a new instance
NS_ENSURE_FALSE(sInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothAvrcpManager* manager = new BluetoothAvrcpManager();
sBluetoothAvrcpManager = manager;
// Create a new instance and return
sBluetoothAvrcpManager = new BluetoothAvrcpManager();
return sBluetoothAvrcpManager;
}
@ -318,6 +322,9 @@ public:
sBtAvrcpInterface->SetNotificationHandler(nullptr);
sBtAvrcpInterface = nullptr;
sBluetoothAvrcpManager->Uninit();
sBluetoothAvrcpManager = nullptr;
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
}
@ -330,6 +337,9 @@ public:
sBtAvrcpInterface->SetNotificationHandler(nullptr);
sBtAvrcpInterface = nullptr;
sBluetoothAvrcpManager->Uninit();
sBluetoothAvrcpManager = nullptr;
if (mRes) {
mRes->Deinit();
}

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

@ -71,6 +71,7 @@ private:
BluetoothAvrcpManager();
void Uninit();
void HandleShutdown();
void NotifyConnectionStatusChanged();

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

@ -389,26 +389,39 @@ BluetoothGattManager::Get()
NS_ENSURE_FALSE(mInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothGattManager* manager = new BluetoothGattManager();
NS_ENSURE_TRUE(manager->Init(), nullptr);
RefPtr<BluetoothGattManager> manager = new BluetoothGattManager();
NS_ENSURE_SUCCESS(manager->Init(), nullptr);
sBluetoothGattManager = manager;
return sBluetoothGattManager;
}
bool
nsresult
BluetoothGattManager::Init()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, false);
NS_ENSURE_TRUE(obs, NS_ERROR_NOT_AVAILABLE);
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (NS_FAILED(rv)) {
BT_WARNING("Failed to add observers!");
return false;
return rv;
}
return true;
return NS_OK;
}
void
BluetoothGattManager::Uninit()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
}
class BluetoothGattManager::RegisterModuleResultHandler final
@ -569,6 +582,11 @@ public:
sBluetoothGattInterface->SetNotificationHandler(nullptr);
sBluetoothGattInterface = nullptr;
sClients = nullptr;
sServers = nullptr;
sBluetoothGattManager->Uninit();
sBluetoothGattManager = nullptr;
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
@ -584,6 +602,9 @@ public:
sClients = nullptr;
sServers = nullptr;
sBluetoothGattManager->Uninit();
sBluetoothGattManager = nullptr;
if (mRes) {
mRes->Deinit();
}
@ -4090,13 +4111,7 @@ BluetoothGattManager::BluetoothGattManager()
{ }
BluetoothGattManager::~BluetoothGattManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
}
{ }
NS_IMETHODIMP
BluetoothGattManager::Observe(nsISupports* aSubject,

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

@ -216,8 +216,9 @@ private:
class ServerSendIndicationResultHandler;
BluetoothGattManager();
bool Init();
nsresult Init();
void Uninit();
void HandleShutdown();
void RegisterClientNotification(BluetoothGattStatus aStatus,

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

@ -84,6 +84,8 @@ BluetoothMapSmsManager::HandleShutdown()
sInShutdown = true;
Disconnect(nullptr);
Uninit();
sMapSmsManager = nullptr;
}
@ -98,27 +100,19 @@ BluetoothMapSmsManager::BluetoothMapSmsManager()
}
BluetoothMapSmsManager::~BluetoothMapSmsManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return;
}
{ }
NS_WARN_IF(NS_FAILED(
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
}
bool
nsresult
BluetoothMapSmsManager::Init()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return false;
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_WARN_IF(NS_FAILED(
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)))) {
return false;
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
/**
@ -130,7 +124,64 @@ BluetoothMapSmsManager::Init()
* absence of read events when device boots up.
*/
return true;
return NS_OK;
}
void
BluetoothMapSmsManager::Uninit()
{
if (mMasServerSocket) {
mMasServerSocket->SetObserver(nullptr);
if (mMasServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasServerSocket->Close();
}
mMasServerSocket = nullptr;
}
if (mMasSocket) {
mMasSocket->SetObserver(nullptr);
if (mMasSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasSocket->Close();
}
mMasSocket = nullptr;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return;
}
NS_WARN_IF(NS_FAILED(
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
}
// static
void
BluetoothMapSmsManager::InitMapSmsInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRes) {
aRes->Init();
}
}
// static
void
BluetoothMapSmsManager::DeinitMapSmsInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sMapSmsManager) {
sMapSmsManager->Uninit();
sMapSmsManager = nullptr;
}
if (aRes) {
aRes->Deinit();
}
}
//static
@ -150,8 +201,8 @@ BluetoothMapSmsManager::Get()
}
// Create a new instance, register, and return
BluetoothMapSmsManager *manager = new BluetoothMapSmsManager();
if (NS_WARN_IF(!manager->Init())) {
RefPtr<BluetoothMapSmsManager> manager = new BluetoothMapSmsManager();
if (NS_WARN_IF(NS_FAILED(manager->Init()))) {
return nullptr;
}
@ -175,10 +226,11 @@ BluetoothMapSmsManager::Listen()
* BT stops; otherwise no more read events would be received even if
* BT restarts.
*/
if (mMasServerSocket) {
if (mMasServerSocket &&
mMasServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasServerSocket->Close();
mMasServerSocket = nullptr;
}
mMasServerSocket = nullptr;
mMasServerSocket = new BluetoothSocket(this);
@ -1510,7 +1562,17 @@ BluetoothMapSmsManager::OnSocketConnectError(BluetoothSocket* aSocket)
}
// MAS socket connection error
if (mMasServerSocket &&
mMasServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasServerSocket->Close();
}
mMasServerSocket = nullptr;
if (mMasSocket &&
mMasSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mMasSocket->Close();
}
mMasSocket = nullptr;
}
@ -1541,6 +1603,7 @@ BluetoothMapSmsManager::OnSocketDisconnect(BluetoothSocket* aSocket)
// MAS socket is disconnected
AfterMapSmsDisconnected();
mDeviceAddress.Clear();
mMasSocket = nullptr;
Listen();

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

@ -86,7 +86,10 @@ public:
// By defualt SMS/MMS is default supported
static const int SDP_SMS_MMS_INSTANCE_ID = 0;
static void InitMapSmsInterface(BluetoothProfileResultHandler* aRes);
static void DeinitMapSmsInterface(BluetoothProfileResultHandler* aRes);
static BluetoothMapSmsManager* Get();
bool Listen();
/**
@ -194,7 +197,9 @@ protected:
private:
BluetoothMapSmsManager();
bool Init();
nsresult Init();
void Uninit();
void HandleShutdown();
void ReplyToConnect();

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

@ -214,31 +214,24 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
{ }
BluetoothOppManager::~BluetoothOppManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
{ }
if (NS_FAILED(obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED))) {
BT_WARNING("Failed to remove volume observer!");
}
}
bool
nsresult
BluetoothOppManager::Init()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, false);
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
NS_ENSURE_TRUE(obs, NS_ERROR_NOT_AVAILABLE);
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (NS_FAILED(rv)) {
BT_WARNING("Failed to add shutdown observer!");
return false;
return rv;
}
if (NS_FAILED(obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false))) {
rv = obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false);
if (NS_FAILED(rv)) {
BT_WARNING("Failed to add ns volume observer!");
return false;
return rv;
}
/**
@ -250,7 +243,67 @@ BluetoothOppManager::Init()
* absence of read events when device boots up.
*/
return true;
return NS_OK;
}
void
BluetoothOppManager::Uninit()
{
if (mServerSocket) {
mServerSocket->SetObserver(nullptr);
if (mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
}
mServerSocket = nullptr;
}
if (mSocket) {
mSocket->SetObserver(nullptr);
if (mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mSocket->Close();
}
mSocket = nullptr;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
BT_WARNING("Failed to remove shutdown observer!");
}
if (NS_FAILED(obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED))) {
BT_WARNING("Failed to remove volume observer!");
}
}
// static
void
BluetoothOppManager::InitOppInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRes) {
aRes->Init();
}
}
// static
void
BluetoothOppManager::DeinitOppInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sBluetoothOppManager) {
sBluetoothOppManager->Uninit();
sBluetoothOppManager = nullptr;
}
if (aRes) {
aRes->Deinit();
}
}
//static
@ -268,10 +321,11 @@ BluetoothOppManager::Get()
NS_ENSURE_FALSE(sInShutdown, nullptr);
// Create a new instance, register, and return
BluetoothOppManager *manager = new BluetoothOppManager();
NS_ENSURE_TRUE(manager->Init(), nullptr);
RefPtr<BluetoothOppManager> manager = new BluetoothOppManager();
NS_ENSURE_SUCCESS(manager->Init(), nullptr);
sBluetoothOppManager = manager;
return sBluetoothOppManager;
}
@ -281,10 +335,11 @@ BluetoothOppManager::ConnectInternal(const BluetoothAddress& aDeviceAddress)
MOZ_ASSERT(NS_IsMainThread());
// Stop listening because currently we only support one connection at a time.
if (mServerSocket) {
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
mServerSocket = nullptr;
}
mServerSocket = nullptr;
mIsServer = false;
@ -310,6 +365,8 @@ BluetoothOppManager::HandleShutdown()
MOZ_ASSERT(NS_IsMainThread());
sInShutdown = true;
Disconnect(nullptr);
Uninit();
sBluetoothOppManager = nullptr;
}
@ -356,10 +413,11 @@ BluetoothOppManager::Listen()
* BT stops; otherwise no more read events would be received even if
* BT restarts.
*/
if (mServerSocket) {
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
mServerSocket = nullptr;
}
mServerSocket = nullptr;
mServerSocket = new BluetoothSocket(this);
@ -1526,7 +1584,16 @@ BluetoothOppManager::OnSocketConnectError(BluetoothSocket* aSocket)
{
BT_LOGR("[%s]", (mIsServer)? "server" : "client");
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
}
mServerSocket = nullptr;
if (mSocket &&
mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mSocket->Close();
}
mSocket = nullptr;
if (!mIsServer) {
@ -1576,7 +1643,8 @@ BluetoothOppManager::OnSocketDisconnect(BluetoothSocket* aSocket)
mDeviceAddress.Clear();
mSuccessFlag = false;
mSocket = nullptr;
mSocket = nullptr; // should already be closed
// Listen as a server if there's no more batch to process
if (!ProcessNextBatch()) {
Listen();

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

@ -40,6 +40,7 @@ class BluetoothOppManager : public BluetoothSocketObserver
class SendSocketDataTask;
public:
BT_DECL_PROFILE_MGR_BASE
BT_DECL_SOCKET_OBSERVER
virtual void GetName(nsACString& aName)
@ -49,7 +50,10 @@ public:
static const int MAX_PACKET_LENGTH = 0xFFFE;
static void InitOppInterface(BluetoothProfileResultHandler* aRes);
static void DeinitOppInterface(BluetoothProfileResultHandler* aRes);
static BluetoothOppManager* Get();
void ClientDataHandler(mozilla::ipc::UnixSocketBuffer* aMessage);
void ServerDataHandler(mozilla::ipc::UnixSocketBuffer* aMessage);
@ -75,7 +79,8 @@ protected:
private:
BluetoothOppManager();
bool Init();
nsresult Init();
void Uninit();
void HandleShutdown();
void HandleVolumeStateChanged(nsISupports* aSubject);

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

@ -94,6 +94,8 @@ BluetoothPbapManager::HandleShutdown()
sInShutdown = true;
Disconnect(nullptr);
Uninit();
sPbapManager = nullptr;
}
@ -105,27 +107,19 @@ BluetoothPbapManager::BluetoothPbapManager() : mPhonebookSizeRequired(false)
}
BluetoothPbapManager::~BluetoothPbapManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return;
}
{ }
NS_WARN_IF(NS_FAILED(
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
}
bool
nsresult
BluetoothPbapManager::Init()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return false;
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_WARN_IF(NS_FAILED(
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)))) {
return false;
auto rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
/**
@ -137,7 +131,64 @@ BluetoothPbapManager::Init()
* absence of read events when device boots up.
*/
return true;
return NS_OK;
}
void
BluetoothPbapManager::Uninit()
{
if (mServerSocket) {
mServerSocket->SetObserver(nullptr);
if (mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
}
mServerSocket = nullptr;
}
if (mSocket) {
mSocket->SetObserver(nullptr);
if (mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mSocket->Close();
}
mSocket = nullptr;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return;
}
NS_WARN_IF(NS_FAILED(
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)));
}
// static
void
BluetoothPbapManager::InitPbapInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRes) {
aRes->Init();
}
}
// static
void
BluetoothPbapManager::DeinitPbapInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (sPbapManager) {
sPbapManager->Uninit();
sPbapManager = nullptr;
}
if (aRes) {
aRes->Deinit();
}
}
//static
@ -157,8 +208,8 @@ BluetoothPbapManager::Get()
}
// Create a new instance, register, and return
BluetoothPbapManager *manager = new BluetoothPbapManager();
if (NS_WARN_IF(!manager->Init())) {
RefPtr<BluetoothPbapManager> manager = new BluetoothPbapManager();
if (NS_WARN_IF(NS_FAILED(manager->Init()))) {
return nullptr;
}
@ -181,10 +232,11 @@ BluetoothPbapManager::Listen()
* BT stops; otherwise no more read events would be received even if
* BT restarts.
*/
if (mServerSocket) {
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
mServerSocket = nullptr;
}
mServerSocket = nullptr;
mServerSocket = new BluetoothSocket(this);
@ -1131,7 +1183,16 @@ BluetoothPbapManager::OnSocketConnectSuccess(BluetoothSocket* aSocket)
void
BluetoothPbapManager::OnSocketConnectError(BluetoothSocket* aSocket)
{
if (mServerSocket &&
mServerSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mServerSocket->Close();
}
mServerSocket = nullptr;
if (mSocket &&
mSocket->GetConnectionStatus() != SOCKET_DISCONNECTED) {
mSocket->Close();
}
mSocket = nullptr;
}
@ -1147,7 +1208,8 @@ BluetoothPbapManager::OnSocketDisconnect(BluetoothSocket* aSocket)
AfterPbapDisconnected();
mDeviceAddress.Clear();
mSocket = nullptr;
mSocket = nullptr; // should already be closed
Listen();
}

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

@ -67,7 +67,10 @@ public:
static const int MAX_PACKET_LENGTH = 0xFFFE;
static const int DIGEST_LENGTH = 16;
static void InitPbapInterface(BluetoothProfileResultHandler* aRes);
static void DeinitPbapInterface(BluetoothProfileResultHandler* aRes);
static BluetoothPbapManager* Get();
bool Listen();
/**
@ -146,7 +149,9 @@ protected:
private:
BluetoothPbapManager();
bool Init();
nsresult Init();
void Uninit();
void HandleShutdown();
void ReplyToConnect(const nsAString& aPassword = EmptyString());

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

@ -138,6 +138,10 @@ public:
void Init() override
{
static void (* const sInitManager[])(BluetoothProfileResultHandler*) = {
BluetoothMapSmsManager::InitMapSmsInterface,
BluetoothOppManager::InitOppInterface,
BluetoothPbapManager::InitPbapInterface,
BluetoothHidManager::InitHidInterface,
BluetoothHfpManager::InitHfpInterface,
BluetoothA2dpManager::InitA2dpInterface,
BluetoothAvrcpManager::InitAvrcpInterface,
@ -280,14 +284,15 @@ BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
static BluetoothProfileManagerBase* sProfiles[] = {
BluetoothHfpManager::Get(),
BluetoothProfileManagerBase* sProfiles[] = {
// BluetoothGattManager not handled here
BluetoothAvrcpManager::Get(),
BluetoothA2dpManager::Get(),
BluetoothOppManager::Get(),
BluetoothHfpManager::Get(),
BluetoothHidManager::Get(),
BluetoothPbapManager::Get(),
BluetoothMapSmsManager::Get(),
BluetoothHidManager::Get()
BluetoothOppManager::Get(),
BluetoothMapSmsManager::Get()
};
// Disconnect all connected profiles
@ -2037,7 +2042,11 @@ BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState)
BluetoothGattManager::DeinitGattInterface,
BluetoothAvrcpManager::DeinitAvrcpInterface,
BluetoothA2dpManager::DeinitA2dpInterface,
BluetoothHfpManager::DeinitHfpInterface
BluetoothHfpManager::DeinitHfpInterface,
BluetoothHidManager::DeinitHidInterface,
BluetoothPbapManager::DeinitPbapInterface,
BluetoothOppManager::DeinitOppInterface,
BluetoothMapSmsManager::DeinitMapSmsInterface
};
// Return error if BluetoothService is unavailable

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

@ -20,24 +20,6 @@ using namespace mozilla::ipc;
USING_BLUETOOTH_NAMESPACE
static const size_t MAX_READ_SIZE = 1 << 16;
static BluetoothSocketInterface* sBluetoothSocketInterface;
// helper functions
static bool
EnsureBluetoothSocketHalLoad()
{
if (sBluetoothSocketInterface) {
return true;
}
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
NS_ENSURE_TRUE(btInf, false);
sBluetoothSocketInterface = btInf->GetBluetoothSocketInterface();
NS_ENSURE_TRUE(sBluetoothSocketInterface, false);
return true;
}
class mozilla::dom::bluetooth::DroidSocketImpl
: public mozilla::ipc::UnixFdWatcher
@ -429,24 +411,20 @@ private:
class InvokeAcceptTask final : public SocketTask<DroidSocketImpl>
{
public:
InvokeAcceptTask(DroidSocketImpl* aImpl, int aFd)
InvokeAcceptTask(DroidSocketImpl* aImpl, int aListenFd)
: SocketTask<DroidSocketImpl>(aImpl)
, mFd(aFd)
, mListenFd(aListenFd)
{ }
void Run() override
{
MOZ_ASSERT(GetIO()->IsConsumerThread());
MOZ_ASSERT(sBluetoothSocketInterface);
BluetoothSocketResultHandler* res = new AcceptResultHandler(GetIO());
GetIO()->mConsumer->SetCurrentResultHandler(res);
sBluetoothSocketInterface->Accept(mFd, res);
GetIO()->mConsumer->Accept(mListenFd, new AcceptResultHandler(GetIO()));
}
private:
int mFd;
int mListenFd;
};
void
@ -581,22 +559,27 @@ DroidSocketImpl::DiscardBuffer()
//
BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver)
: mObserver(aObserver)
: mSocketInterface(nullptr)
, mObserver(aObserver)
, mCurrentRes(nullptr)
, mImpl(nullptr)
{
MOZ_ASSERT(aObserver);
MOZ_COUNT_CTOR_INHERITED(BluetoothSocket, DataSocket);
EnsureBluetoothSocketHalLoad();
}
BluetoothSocket::~BluetoothSocket()
{
MOZ_ASSERT(!mImpl); // Socket is closed
MOZ_COUNT_DTOR_INHERITED(BluetoothSocket, DataSocket);
}
void
BluetoothSocket::SetObserver(BluetoothSocketObserver* aObserver)
{
mObserver = aObserver;
}
class ConnectSocketResultHandler final : public BluetoothSocketResultHandler
{
public:
@ -655,6 +638,11 @@ BluetoothSocket::Connect(const BluetoothAddress& aDeviceAddress,
{
MOZ_ASSERT(!mImpl);
auto rv = LoadSocketInterface();
if (NS_FAILED(rv)) {
return rv;
}
SetConnectionStatus(SOCKET_CONNECTING);
mImpl = new DroidSocketImpl(aConsumerLoop, aIOLoop, this);
@ -662,7 +650,7 @@ BluetoothSocket::Connect(const BluetoothAddress& aDeviceAddress,
BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl);
SetCurrentResultHandler(res);
sBluetoothSocketInterface->Connect(
mSocketInterface->Connect(
aDeviceAddress, aType,
aServiceUuid, aChannel,
aEncrypt, aAuth, res);
@ -719,8 +707,13 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
{
MOZ_ASSERT(!mImpl);
auto rv = LoadSocketInterface();
if (NS_FAILED(rv)) {
return rv;
}
BluetoothServiceName serviceName;
nsresult rv = StringToServiceName(aServiceName, serviceName);
rv = StringToServiceName(aServiceName, serviceName);
if (NS_FAILED(rv)) {
return rv;
}
@ -732,7 +725,7 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
BluetoothSocketResultHandler* res = new ListenResultHandler(mImpl);
SetCurrentResultHandler(res);
sBluetoothSocketInterface->Listen(
mSocketInterface->Listen(
aType,
serviceName, aServiceUuid, aChannel,
aEncrypt, aAuth, res);
@ -751,12 +744,26 @@ BluetoothSocket::Listen(const nsAString& aServiceName,
MessageLoop::current(), XRE_GetIOMessageLoop());
}
nsresult
BluetoothSocket::Accept(int aListenFd, BluetoothSocketResultHandler* aRes)
{
auto rv = LoadSocketInterface();
if (NS_FAILED(rv)) {
return rv;
}
SetCurrentResultHandler(aRes);
mSocketInterface->Accept(aListenFd, aRes);
return NS_OK;
}
void
BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer)
{
MOZ_ASSERT(mObserver);
mObserver->ReceiveSocketData(this, aBuffer);
if (mObserver) {
mObserver->ReceiveSocketData(this, aBuffer);
}
}
// |DataSocket|
@ -778,50 +785,86 @@ BluetoothSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
void
BluetoothSocket::Close()
{
MOZ_ASSERT(sBluetoothSocketInterface);
if (!mImpl) {
return;
}
MOZ_ASSERT(mImpl->IsConsumerThread());
// Stop any watching |SocketMessageWatcher|
if (mCurrentRes) {
sBluetoothSocketInterface->Close(mCurrentRes);
}
// From this point on, we consider mImpl as being deleted.
// We sever the relationship here so any future calls to listen or connect
// will create a new implementation.
mImpl->ShutdownOnConsumerThread();
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mImpl));
mImpl = nullptr;
NotifyDisconnect();
}
void
BluetoothSocket::OnConnectSuccess()
{
MOZ_ASSERT(mObserver);
SetCurrentResultHandler(nullptr);
mObserver->OnSocketConnectSuccess(this);
if (mObserver) {
mObserver->OnSocketConnectSuccess(this);
}
}
void
BluetoothSocket::OnConnectError()
{
MOZ_ASSERT(mObserver);
auto observer = mObserver;
SetCurrentResultHandler(nullptr);
mObserver->OnSocketConnectError(this);
Cleanup();
if (observer) {
observer->OnSocketConnectError(this);
}
}
void
BluetoothSocket::OnDisconnect()
{
MOZ_ASSERT(mObserver);
mObserver->OnSocketDisconnect(this);
auto observer = mObserver;
Cleanup();
if (observer) {
observer->OnSocketDisconnect(this);
}
}
nsresult
BluetoothSocket::LoadSocketInterface()
{
if (mSocketInterface) {
return NS_OK;
}
auto interface = BluetoothInterface::GetInstance();
NS_ENSURE_TRUE(!!interface, NS_ERROR_FAILURE);
auto socketInterface = interface->GetBluetoothSocketInterface();
NS_ENSURE_TRUE(!!socketInterface, NS_ERROR_FAILURE);
mSocketInterface = socketInterface;
return NS_OK;
}
void
BluetoothSocket::Cleanup()
{
MOZ_ASSERT(mSocketInterface);
MOZ_ASSERT(mImpl);
MOZ_ASSERT(mImpl->IsConsumerThread());
// Stop any watching |SocketMessageWatcher|
if (mCurrentRes) {
mSocketInterface->Close(mCurrentRes);
}
// From this point on, we consider mImpl as being deleted. We
// sever the relationship here so any future calls to listen
// or connect will create a new implementation.
mImpl->ShutdownOnConsumerThread();
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mImpl));
mImpl = nullptr;
mSocketInterface = nullptr;
mObserver = nullptr;
mCurrentRes = nullptr;
mDeviceAddress.Clear();
}

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

@ -14,6 +14,7 @@ class MessageLoop;
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothSocketInterface;
class BluetoothSocketObserver;
class BluetoothSocketResultHandler;
class DroidSocketImpl;
@ -24,6 +25,8 @@ public:
BluetoothSocket(BluetoothSocketObserver* aObserver);
~BluetoothSocket();
void SetObserver(BluetoothSocketObserver* aObserver);
nsresult Connect(const BluetoothAddress& aDeviceAddress,
const BluetoothUuid& aServiceUuid,
BluetoothSocketType aType,
@ -52,6 +55,8 @@ public:
int aChannel,
bool aAuth, bool aEncrypt);
nsresult Accept(int aListenFd, BluetoothSocketResultHandler* aRes);
/**
* Method to be called whenever data is received. This is only called on the
* consumer thread.
@ -70,11 +75,6 @@ public:
mDeviceAddress = aDeviceAddress;
}
inline void SetCurrentResultHandler(BluetoothSocketResultHandler* aRes)
{
mCurrentRes = aRes;
}
// Methods for |DataSocket|
//
@ -90,6 +90,15 @@ public:
void OnDisconnect() override;
private:
nsresult LoadSocketInterface();
void Cleanup();
inline void SetCurrentResultHandler(BluetoothSocketResultHandler* aRes)
{
mCurrentRes = aRes;
}
BluetoothSocketInterface* mSocketInterface;
BluetoothSocketObserver* mObserver;
BluetoothSocketResultHandler* mCurrentRes;
DroidSocketImpl* mImpl;

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

@ -176,6 +176,8 @@ BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
sBluetoothHfpManager = nullptr;
/**
* TODO:
* Implement DeinitHfpInterface() for applications that want to create SCO

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

@ -446,6 +446,7 @@ public:
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
sBluetoothHfpInterface = nullptr;
sBluetoothHfpManager = nullptr;
if (mRes) {
mRes->OnError(NS_ERROR_FAILURE);
@ -458,6 +459,7 @@ public:
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
sBluetoothHfpInterface = nullptr;
sBluetoothHfpManager = nullptr;
if (mRes) {
mRes->Deinit();

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

@ -78,6 +78,30 @@ BluetoothHidManager::~BluetoothHidManager()
}
}
// static
void
BluetoothHidManager::InitHidInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
if (aRes) {
aRes->Init();
}
}
// static
void
BluetoothHidManager::DeinitHidInterface(BluetoothProfileResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
sBluetoothHidManager = nullptr;
if (aRes) {
aRes->Deinit();
}
}
//static
BluetoothHidManager*
BluetoothHidManager::Get()

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

@ -22,6 +22,8 @@ public:
aName.AssignLiteral("HID");
}
static void InitHidInterface(BluetoothProfileResultHandler* aRes);
static void DeinitHidInterface(BluetoothProfileResultHandler* aRes);
static BluetoothHidManager* Get();
// HID-specific functions

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

@ -36,7 +36,6 @@ const kSmsDeletedObserverTopic = "sms-deleted";
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
const kNetworkConnStateChangedTopic = "network-connection-state-changed";
const kPrefRilRadioDisabled = "ril.radio.disabled";
const kPrefMmsDebuggingEnabled = "mms.debugging.enabled";
// HTTP status codes:
@ -194,18 +193,12 @@ function getDefaultServiceId() {
}
/**
* Return Radio disabled state.
* Return radio disabled state.
*/
function getRadioDisabledState() {
let state;
try {
state = Services.prefs.getBoolPref(kPrefRilRadioDisabled);
} catch (e) {
if (DEBUG) debug("Getting preference 'ril.radio.disabled' fails.");
state = false;
}
return state;
function isRadioOff(aServiceId) {
let connection = gMobileConnectionService.getItemByServiceId(aServiceId);
return connection.radioState
!== Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED;
}
/**
@ -422,7 +415,7 @@ MmsConnection.prototype = {
this.pendingCallbacks.push(callback);
let errorStatus;
if (getRadioDisabledState()) {
if (isRadioOff(this.serviceId)) {
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
errorStatus = _HTTP_STATUS_RADIO_DISABLED;
} else if (this.getCardState() != Ci.nsIIcc.CARD_STATE_READY) {
@ -993,7 +986,8 @@ function CancellableTransaction(cancellableId, serviceId) {
this.isCancelled = false;
}
CancellableTransaction.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsIMobileConnectionListener]),
// The timer for retrying sending or retrieving process.
timer: null,
@ -1010,8 +1004,9 @@ CancellableTransaction.prototype = {
if (!this.isObserversAdded) {
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
Services.obs.addObserver(this, kSmsDeletedObserverTopic, false);
Services.prefs.addObserver(kPrefRilRadioDisabled, this, false);
Services.prefs.addObserver(kPrefDefaultServiceId, this, false);
gMobileConnectionService
.getItemByServiceId(this.serviceId).registerListener(this);
this.isObserversAdded = true;
}
@ -1023,8 +1018,9 @@ CancellableTransaction.prototype = {
if (this.isObserversAdded) {
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
Services.obs.removeObserver(this, kSmsDeletedObserverTopic);
Services.prefs.removeObserver(kPrefRilRadioDisabled, this);
Services.prefs.removeObserver(kPrefDefaultServiceId, this);
gMobileConnectionService
.getItemByServiceId(this.serviceId).unregisterListener(this);
this.isObserversAdded = false;
}
},
@ -1080,18 +1076,35 @@ CancellableTransaction.prototype = {
break;
}
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID: {
if (data == kPrefRilRadioDisabled) {
if (getRadioDisabledState()) {
this.cancelRunning(_MMS_ERROR_RADIO_DISABLED);
}
} else if (data === kPrefDefaultServiceId &&
if (data === kPrefDefaultServiceId &&
this.serviceId != getDefaultServiceId()) {
this.cancelRunning(_MMS_ERROR_SIM_CARD_CHANGED);
}
break;
}
}
}
},
// nsIMobileConnectionListener
notifyVoiceChanged: function() {},
notifyDataChanged: function() {},
notifyDataError: function(message) {},
notifyCFStateChanged: function(action, reason, number, timeSeconds, serviceClass) {},
notifyEmergencyCbModeChanged: function(active, timeoutMs) {},
notifyOtaStatusChanged: function(status) {},
notifyRadioStateChanged: function() {
if (isRadioOff(this.serviceId)) {
this.cancelRunning(_MMS_ERROR_RADIO_DISABLED);
}
},
notifyClirModeChanged: function(mode) {},
notifyLastKnownNetworkChanged: function() {},
notifyLastKnownHomeNetworkChanged: function() {},
notifyNetworkSelectionModeChanged: function() {},
notifyDeviceIdentitiesChanged: function() {}
};
/**
@ -2388,7 +2401,7 @@ MmsService.prototype = {
}
// Check radio state in prior to default service Id.
if (getRadioDisabledState()) {
if (isRadioOff(aServiceId)) {
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
sendTransactionCb(mmsMessage,
Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR,
@ -2502,7 +2515,13 @@ MmsService.prototype = {
// Hence, for manual retrieving, instead of checking radio state later
// in MmsConnection.acquire(), We have to check radio state in prior to
// iccId to return the error correctly.
if (getRadioDisabledState()) {
let numRadioInterfaces = gMobileConnectionService.numItems;
let isAllRadioOff = true;
for (let serviceId = 0; serviceId < numRadioInterfaces; serviceId++) {
isAllRadioOff &= isRadioOff(serviceId);
}
if (isAllRadioOff) {
if (DEBUG) debug("Error! Radio is disabled when retrieving MMS.");
aRequest.notifyGetMessageFailed(
Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR);

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

@ -663,3 +663,60 @@ function runIfMultiSIM(aTest) {
return Promise.resolve();
}
}
/**
* Helper to enable/disable connection radio state.
*
* @param aConnection
* connection to enable / disable
* @param aEnabled
* True to enable the radio.
* @return a Promise object.
*/
function setRadioEnabled(aConnection, aEnabled) {
log("setRadioEnabled to " + aEnabled);
let deferred = Promise.defer();
let finalState = (aEnabled) ? "enabled" : "disabled";
if (aConnection.radioState == finalState) {
return deferred.resolve(aConnection);
}
aConnection.onradiostatechange = function() {
log("Received 'radiostatechange', radioState: " + aConnection.radioState);
if (aConnection.radioState == finalState) {
deferred.resolve(aConnection);
aConnection.onradiostatechange = null;
}
};
let req = aConnection.setRadioEnabled(aEnabled);
req.onsuccess = function() {
log("setRadioEnabled success");
};
req.onerror = function() {
ok(false, "setRadioEnabled should not fail");
deferred.reject();
};
return deferred.promise;
}
/**
* Helper to enable/disable all connections radio state.
*
* @param aEnabled
* True to enable the radio.
* @return a Promise object.
*/
function setAllRadioEnabled(aEnabled) {
let promises = []
for (let i = 0; i < window.navigator.mozMobileConnections.length; ++i) {
promises.push(ensureMobileConnection(i)
.then((connection) => setRadioEnabled(connection, aEnabled)));
}
return Promise.all(promises);
}

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

@ -2,6 +2,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
// We apply "chrome" context to be more flexible to
// specify the content of M-Notification.ind such as iccId
// for different kinds of testing.
@ -17,11 +18,17 @@ var gMobileMessageDatabaseService =
.getService(Ci.nsIGonkMobileMessageDatabaseService);
var gUuidGenerator =
Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
var gMmsService = Cc["@mozilla.org/mms/gonkmmsservice;1"]
.getService(Ci.nsIMmsService);
var gMmsService =
Cc["@mozilla.org/mms/gonkmmsservice;1"].getService(Ci.nsIMmsService);
var gMobileConnectionService =
Cc["@mozilla.org/mobileconnection/mobileconnectionservice;1"]
.getService(Ci.nsIMobileConnectionService);
var gIccService =
Cc["@mozilla.org/icc/gonkiccservice;1"].getService(Ci.nsIIccService);
function saveMmsNotification() {
log("saveMmsNotification()");
@ -101,23 +108,111 @@ function retrieveMmsWithFailure(aId) {
return deferred.promise;
}
function testRetrieve(aCause, aInit, aCleanup) {
function testRetrieve(aCause) {
log("testRetrieve: aCause = " + aCause);
return Promise.resolve()
.then(() => { if (aInit) aInit(); })
.then(saveMmsNotification)
.then((message) => retrieveMmsWithFailure(message.id))
.then((response) => verifyErrorCause(response, aCause))
.then(() => { if (aCleanup) aCleanup(); });
.then((response) => verifyErrorCause(response, aCause));
}
var setRadioDisabled = function(aDisabled) {
log("set ril.radio.disabled to " + aDisabled);
Services.prefs.setBoolPref("ril.radio.disabled", aDisabled);
};
function setRadioEnabled(aConnection, aEnabled) {
let deferred = Promise.defer();
let finalState = (aEnabled) ?
Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED :
Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED;
testRetrieve(Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR,
setRadioDisabled.bind(null, true),
setRadioDisabled.bind(null, false))
if (aConnection.radioState == finalState) {
return deferred.resolve(aConnection);
}
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionListener]),
notifyVoiceChanged: function() {},
notifyDataChanged: function() {},
notifyDataError: function(message) {},
notifyCFStateChanged: function(action, reason, number, timeSeconds, serviceClass) {},
notifyEmergencyCbModeChanged: function(active, timeoutMs) {},
notifyOtaStatusChanged: function(status) {},
notifyRadioStateChanged: function() {
log("setRadioEnabled state changed to " + aConnection.radioState);
if (aConnection.radioState == finalState) {
aConnection.unregisterListener(listener);
deferred.resolve(aConnection);
}
},
notifyClirModeChanged: function(mode) {},
notifyLastKnownNetworkChanged: function() {},
notifyLastKnownHomeNetworkChanged: function() {},
notifyNetworkSelectionModeChanged: function() {},
notifyDeviceIdentitiesChanged: function() {}
};
let callback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionCallback]),
notifySuccess() {},
notifySuccessWithBoolean(result) {},
notifyGetNetworksSuccess(count, networks) {},
notifyGetCallForwardingSuccess(count, results) {},
notifyGetCallBarringSuccess(program, enabled, serviceClass) {},
notifyGetCallWaitingSuccess(serviceClass) {},
notifyGetClirStatusSuccess(n, m) {},
notifyGetPreferredNetworkTypeSuccess(type) {},
notifyGetRoamingPreferenceSuccess(mode) {},
notifyError(name) {
log("setRadioEnabled reject");
aConnection.unregisterListener(listener);
deferred.reject();
}
};
aConnection.registerListener(listener);
aConnection.setRadioEnabled(aEnabled, callback);
return deferred.promise;
}
function setAllRadioEnabled(aEnabled) {
log("setAllRadioEnabled connection number = " +
gMobileConnectionService.numItems);
let promises = [];
for (let i = 0; i < gMobileConnectionService.numItems; ++i) {
promises.push(setRadioEnabled(
gMobileConnectionService.getItemByServiceId(i), aEnabled));
}
return Promise.all(promises);
}
function waitIccReady(aIcc) {
let deferred = Promise.defer();
if (aIcc.cardState == Ci.nsIIcc.CARD_STATE_READY) {
return deferred.resolve(aIcc);
}
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccListener]),
notifyStkCommand(aStkProactiveCmd) {},
notifyStkSessionEnd() {},
notifyCardStateChanged() {
if (aIcc.cardState == Ci.nsIIcc.CARD_STATE_READY) {
aIcc.unregisterListener(listener);
deferred.resolve(aIcc);
}
},
notifyIccInfoChanged() {}
};
aIcc.registerListener(listener);
return deferred.promise;
}
function waitAllIccReady() {
let promises = [];
for (let i = 0; i < gMobileConnectionService.numItems; ++i) {
let icc = gIccService.getIccByServiceId(i);
promises.push(waitIccReady(icc));
}
return Promise.all(promises);
}
setAllRadioEnabled(false)
.then(() => testRetrieve(Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR))
.then(() => setAllRadioEnabled(true))
.then(() => waitAllIccReady())
.then(() => testRetrieve(Ci.nsIMobileMessageCallback.SIM_NOT_MATCHED_ERROR))
.then(finish);

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

@ -4,8 +4,6 @@
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
const kPrefRilRadioDisabled = "ril.radio.disabled";
function testSendFailed(aCause, aServiceId) {
log("testSendFailed, aCause: " + aCause + ", aServiceId: " + aServiceId);
let sendParameters;
@ -44,13 +42,9 @@ function testSendFailed(aCause, aServiceId) {
startTestCommon(function testCaseMain() {
return Promise.resolve()
.then(() => {
SpecialPowers.setBoolPref(kPrefRilRadioDisabled, true);
})
.then(() => testSendFailed("RadioDisabledError"))
.then(() => {
SpecialPowers.setBoolPref(kPrefRilRadioDisabled, false);
})
.then(() => setAllRadioEnabled(false))
.then(() => testSendFailed("RadioDisabledError"), 0)
.then(() => setAllRadioEnabled(true))
.then(() => runIfMultiSIM(
() => testSendFailed("NonActiveSimCardError", 1)));
});

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

@ -4,79 +4,6 @@
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
const kPrefRilRadioDisabled = "ril.radio.disabled";
var connection;
function ensureMobileConnection() {
let deferred = Promise.defer();
let permissions = [{
"type": "mobileconnection",
"allow": true,
"context": document,
}];
SpecialPowers.pushPermissions(permissions, function() {
ok(true, "permissions pushed: " + JSON.stringify(permissions));
connection = window.navigator.mozMobileConnections[0];
if (connection) {
log("navigator.mozMobileConnections[0] is instance of " + connection.constructor);
} else {
log("navigator.mozMobileConnections[0] is undefined.");
}
if (connection instanceof MozMobileConnection) {
deferred.resolve(connection);
} else {
deferred.reject();
}
});
return deferred.promise;
}
function waitRadioState(state) {
let deferred = Promise.defer();
waitFor(function() {
deferred.resolve();
}, function() {
return connection.radioState == state;
});
return deferred.promise;
}
function setRadioEnabled(enabled) {
log("setRadioEnabled to " + enabled);
let deferred = Promise.defer();
let finalState = (enabled) ? "enabled" : "disabled";
connection.onradiostatechange = function() {
let state = connection.radioState;
log("Received 'radiostatechange' event, radioState: " + state);
if (state == finalState) {
deferred.resolve();
connection.onradiostatechange = null;
}
};
let req = connection.setRadioEnabled(enabled);
req.onsuccess = function() {
log("setRadioEnabled success");
};
req.onerror = function() {
ok(false, "setRadioEnabled should not fail");
deferred.reject();
};
return deferred.promise;
}
function testSendFailed(aCause) {
log("testSendFailed, aCause: " + aCause);
@ -98,8 +25,7 @@ function testSendFailed(aCause) {
startTestCommon(function testCaseMain() {
return ensureMobileConnection()
.then(() => waitRadioState("enabled"))
.then(() => setRadioEnabled(false))
.then(() => setRadioEnabled(mobileConnection, false))
.then(() => testSendFailed("RadioDisabledError"))
.then(() => setRadioEnabled(true));
.then(() => setRadioEnabled(mobileConnection, true));
});

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

@ -37,7 +37,20 @@
is(sheet.parsingMode, "author",
"author sheet has expected mode");
results[sss.AUTHOR_SHEET] = 1;
} else if (sheet.href === "about:PreferenceStyleSheet") {
is(sheet.parsingMode, "agent",
"about:PreferenceStyleSheet has agent mode");
continue;
} else {
// Ignore sheets we don't care about.
continue;
}
// Check that re-parsing preserves the mode.
let mode = sheet.parsingMode;
domutils.parseStyleSheet(sheet, "body { color: chartreuse; }");
is(sheet.parsingMode, mode,
"check that re-parsing preserved mode " + mode);
}
ok(results[sss.AGENT_SHEET] && results[sss.USER_SHEET] &&

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

@ -2280,12 +2280,6 @@ CSSStyleSheet::ReparseSheet(const nsAString& aInput)
mInner->mFirstChild = nullptr;
mInner->mNameSpaceMap = nullptr;
// allow agent features if the style sheet's principal is the system principal
css::SheetParsingMode parsingMode =
nsContentUtils::IsSystemPrincipal(mInner->mPrincipal)
? css::eAgentSheetFeatures
: css::eAuthorSheetFeatures;
uint32_t lineNumber = 1;
if (mOwningNode) {
nsCOMPtr<nsIStyleSheetLinkingElement> link = do_QueryInterface(mOwningNode);
@ -2297,7 +2291,7 @@ CSSStyleSheet::ReparseSheet(const nsAString& aInput)
nsCSSParser parser(loader, this);
nsresult rv = parser.ParseSheet(aInput, mInner->mSheetURI, mInner->mBaseURI,
mInner->mPrincipal, lineNumber,
parsingMode, &reusableSheets);
mParsingMode, &reusableSheets);
DidDirty(); // we are always 'dirty' here since we always remove rules first
NS_ENSURE_SUCCESS(rv, rv);

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

@ -815,6 +815,7 @@ nsLayoutStylesheetCache::BuildPreferenceSheet(RefPtr<CSSStyleSheet>& aSheet,
nsPresContext* aPresContext)
{
aSheet = new CSSStyleSheet(CORS_NONE, mozilla::net::RP_Default);
aSheet->SetParsingMode(eAgentSheetFeatures);
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nullptr);

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

@ -16,12 +16,21 @@
android:targetSdkVersion="23"/>
#include ../services/manifests/FxAccountAndroidManifest_permissions.xml.in
#include ../services/manifests/SyncAndroidManifest_permissions.xml.in
#ifdef MOZ_ANDROID_SEARCH_ACTIVITY
#include ../search/manifests/SearchAndroidManifest_permissions.xml.in
#endif
<!-- A signature level permission specific to each Firefox version (Android
package name, e.g., org.mozilla.firefox). Use this permission to
broadcast securely within a single Firefox version. This needs to
agree with GlobalConstants.PER_ANDROID_PACKAGE_PERMISSION. -->
<permission
android:name="@ANDROID_PACKAGE_NAME@.permission.PER_ANDROID_PACKAGE"
android:protectionLevel="signature"/>
<uses-permission android:name="@ANDROID_PACKAGE_NAME@.permission.PER_ANDROID_PACKAGE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
@ -356,7 +365,6 @@
</receiver>
#include ../services/manifests/FxAccountAndroidManifest_activities.xml.in
#include ../services/manifests/SyncAndroidManifest_activities.xml.in
#ifdef MOZ_ANDROID_SEARCH_ACTIVITY
#include ../search/manifests/SearchAndroidManifest_activities.xml.in
#endif
@ -463,7 +471,6 @@
#include ../services/manifests/FxAccountAndroidManifest_services.xml.in
#include ../services/manifests/SyncAndroidManifest_services.xml.in
<service
android:name="org.mozilla.gecko.tabqueue.TabReceivedService"

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

@ -194,13 +194,6 @@ public class AppConstants {
false;
//#endif
public static final boolean MOZ_ANDROID_READING_LIST_SERVICE =
//#ifdef MOZ_ANDROID_READING_LIST_SERVICE
true;
//#else
false;
//#endif
public static final boolean MOZ_TELEMETRY_ON_BY_DEFAULT =
//#ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
true;

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

@ -765,7 +765,6 @@ sync_thirdparty_java_files = [
sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozilla/gecko/' + x for x in [
'background/BackgroundService.java',
'background/common/DateUtils.java',
'background/common/EditorBranch.java',
'background/common/GlobalConstants.java',
'background/common/log/Logger.java',
@ -782,12 +781,9 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'background/common/telemetry/TelemetryWrapper.java',
'background/db/CursorDumper.java',
'background/db/Tab.java',
'background/fxa/FxAccount10AuthDelegate.java',
'background/fxa/FxAccount10CreateDelegate.java',
'background/fxa/FxAccount20CreateDelegate.java',
'background/fxa/FxAccount20LoginDelegate.java',
'background/fxa/FxAccountClient.java',
'background/fxa/FxAccountClient10.java',
'background/fxa/FxAccountClient20.java',
'background/fxa/FxAccountClientException.java',
'background/fxa/FxAccountRemoteError.java',
@ -854,7 +850,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'fxa/receivers/FxAccountDeletedReceiver.java',
'fxa/receivers/FxAccountDeletedService.java',
'fxa/receivers/FxAccountUpgradeReceiver.java',
'fxa/sync/FxAccountGlobalSession.java',
'fxa/sync/FxAccountNotificationManager.java',
'fxa/sync/FxAccountProfileService.java',
'fxa/sync/FxAccountSchedulePolicy.java',
@ -870,10 +865,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'sync/CollectionKeys.java',
'sync/CommandProcessor.java',
'sync/CommandRunner.java',
'sync/config/AccountPickler.java',
'sync/config/activities/SelectEnginesActivity.java',
'sync/config/ClientRecordTerminator.java',
'sync/config/ConfigurationMigrator.java',
'sync/CredentialException.java',
'sync/crypto/CryptoException.java',
'sync/crypto/CryptoInfo.java',
@ -886,14 +877,12 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'sync/crypto/PersistedCrypto5Keys.java',
'sync/CryptoRecord.java',
'sync/DelayedWorkTracker.java',
'sync/delegates/BaseGlobalSessionCallback.java',
'sync/delegates/ClientsDataDelegate.java',
'sync/delegates/FreshStartDelegate.java',
'sync/delegates/GlobalSessionCallback.java',
'sync/delegates/JSONRecordFetchDelegate.java',
'sync/delegates/KeyUploadDelegate.java',
'sync/delegates/MetaGlobalDelegate.java',
'sync/delegates/NodeAssignmentCallback.java',
'sync/delegates/WipeServerDelegate.java',
'sync/EngineSettings.java',
'sync/ExtendedJSONObject.java',
@ -901,29 +890,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'sync/HTTPFailureException.java',
'sync/InfoCollections.java',
'sync/InfoCounts.java',
'sync/jpake/BigIntegerHelper.java',
'sync/jpake/Gx3OrGx4IsZeroOrOneException.java',
'sync/jpake/IncorrectZkpException.java',
'sync/jpake/JPakeClient.java',
'sync/jpake/JPakeCrypto.java',
'sync/jpake/JPakeJson.java',
'sync/jpake/JPakeNoActivePairingException.java',
'sync/jpake/JPakeNumGenerator.java',
'sync/jpake/JPakeNumGeneratorRandom.java',
'sync/jpake/JPakeParty.java',
'sync/jpake/stage/CompleteStage.java',
'sync/jpake/stage/ComputeFinalStage.java',
'sync/jpake/stage/ComputeKeyVerificationStage.java',
'sync/jpake/stage/ComputeStepOneStage.java',
'sync/jpake/stage/ComputeStepTwoStage.java',
'sync/jpake/stage/DecryptDataStage.java',
'sync/jpake/stage/DeleteChannel.java',
'sync/jpake/stage/GetChannelStage.java',
'sync/jpake/stage/GetRequestStage.java',
'sync/jpake/stage/JPakeStage.java',
'sync/jpake/stage/PutRequestStage.java',
'sync/jpake/stage/VerifyPairingStage.java',
'sync/jpake/Zkp.java',
'sync/JSONRecordFetcher.java',
'sync/KeyBundleProvider.java',
'sync/MetaGlobal.java',
@ -934,7 +900,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'sync/middleware/Crypto5MiddlewareRepositorySession.java',
'sync/middleware/MiddlewareRepository.java',
'sync/middleware/MiddlewareRepositorySession.java',
'sync/MigrationSentinelSyncStage.java',
'sync/net/AbstractBearerTokenAuthHeaderProvider.java',
'sync/net/AuthHeaderProvider.java',
'sync/net/BaseResource.java',
@ -969,9 +934,6 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'sync/NullClusterURLException.java',
'sync/PersistedMetaGlobal.java',
'sync/PrefsBackoffHandler.java',
'sync/receivers/SyncAccountDeletedReceiver.java',
'sync/receivers/SyncAccountDeletedService.java',
'sync/receivers/UpgradeReceiver.java',
'sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java',
'sync/repositories/android/AndroidBrowserBookmarksRepository.java',
'sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java',
@ -1049,35 +1011,17 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'sync/repositories/StoreTrackingRepositorySession.java',
'sync/Server11PreviousPostFailedException.java',
'sync/Server11RecordPostFailedException.java',
'sync/setup/activities/AccountActivity.java',
'sync/setup/activities/ActivityUtils.java',
'sync/setup/activities/RedirectToSetupActivity.java',
'sync/setup/activities/SendTabData.java',
'sync/setup/activities/SetupFailureActivity.java',
'sync/setup/activities/SetupSuccessActivity.java',
'sync/setup/activities/SetupSyncActivity.java',
'sync/setup/activities/SyncActivity.java',
'sync/setup/activities/WebURLFinder.java',
'sync/setup/activities/WebViewActivity.java',
'sync/setup/auth/AccountAuthenticator.java',
'sync/setup/auth/AuthenticateAccountStage.java',
'sync/setup/auth/AuthenticationResult.java',
'sync/setup/auth/AuthenticatorStage.java',
'sync/setup/auth/EnsureUserExistenceStage.java',
'sync/setup/auth/FetchUserNodeStage.java',
'sync/setup/Constants.java',
'sync/setup/InvalidSyncKeyException.java',
'sync/setup/SyncAccounts.java',
'sync/setup/SyncAuthenticatorService.java',
'sync/SharedPreferencesClientsDataDelegate.java',
'sync/SharedPreferencesNodeAssignmentCallback.java',
'sync/stage/AbstractNonRepositorySyncStage.java',
'sync/stage/AbstractSessionManagingSyncStage.java',
'sync/stage/AndroidBrowserBookmarksServerSyncStage.java',
'sync/stage/AndroidBrowserHistoryServerSyncStage.java',
'sync/stage/CheckPreconditionsStage.java',
'sync/stage/CompletedStage.java',
'sync/stage/EnsureClusterURLStage.java',
'sync/stage/EnsureCrypto5KeysStage.java',
'sync/stage/FennecTabsServerSyncStage.java',
'sync/stage/FetchInfoCollectionsStage.java',
@ -1085,15 +1029,12 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'sync/stage/FormHistoryServerSyncStage.java',
'sync/stage/GlobalSyncStage.java',
'sync/stage/NoSuchStageException.java',
'sync/stage/NoSyncIDException.java',
'sync/stage/PasswordsServerSyncStage.java',
'sync/stage/SafeConstrainedServer11Repository.java',
'sync/stage/ServerSyncStage.java',
'sync/stage/SyncClientsEngineStage.java',
'sync/stage/UploadMetaGlobalStage.java',
'sync/Sync11Configuration.java',
'sync/syncadapter/SyncAdapter.java',
'sync/syncadapter/SyncService.java',
'sync/SyncConfiguration.java',
'sync/SyncConfigurationException.java',
'sync/SyncConstants.java',
@ -1124,29 +1065,3 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'tokenserver/TokenServerException.java',
'tokenserver/TokenServerToken.java',
]]
reading_list_service_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozilla/gecko/' + x for x in [
'reading/ClientMetadata.java',
'reading/ClientReadingListRecord.java',
'reading/FetchSpec.java',
'reading/LocalReadingListStorage.java',
'reading/ReadingListBackoffObserver.java',
'reading/ReadingListChangeAccumulator.java',
'reading/ReadingListClient.java',
'reading/ReadingListClientContentValuesFactory.java',
'reading/ReadingListClientRecordFactory.java',
'reading/ReadingListDeleteDelegate.java',
'reading/ReadingListInvalidAuthenticationException.java',
'reading/ReadingListRecord.java',
'reading/ReadingListRecordDelegate.java',
'reading/ReadingListRecordResponse.java',
'reading/ReadingListRecordUploadDelegate.java',
'reading/ReadingListResponse.java',
'reading/ReadingListStorage.java',
'reading/ReadingListStorageResponse.java',
'reading/ReadingListSyncAdapter.java',
'reading/ReadingListSynchronizer.java',
'reading/ReadingListSynchronizerDelegate.java',
'reading/ReadingListSyncService.java',
'reading/ReadingListWipeDelegate.java',
'reading/ServerReadingListRecord.java',
]]

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

@ -14,6 +14,7 @@ import android.accounts.OperationCanceledException;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.background.fxa.FxAccountUtils;
@ -25,7 +26,6 @@ import org.mozilla.gecko.fxa.login.State;
import org.mozilla.gecko.restrictions.Restrictable;
import org.mozilla.gecko.sync.SyncConfiguration;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.setup.SyncAccounts;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
@ -252,8 +252,7 @@ public class AccountsHelper implements NativeEventListener {
try {
if ("any".equals(kind)) {
response.put("exists", SyncAccounts.syncAccountsExist(mContext) ||
FirefoxAccounts.firefoxAccountsExist(mContext));
response.put("exists", FirefoxAccounts.firefoxAccountsExist(mContext));
callback.sendSuccess(response);
} else if ("fxa".equals(kind)) {
final Account account = FirefoxAccounts.getFirefoxAccount(mContext);
@ -276,9 +275,6 @@ public class AccountsHelper implements NativeEventListener {
}
}
callback.sendSuccess(response);
} else if ("sync11".equals(kind)) {
response.put("exists", SyncAccounts.syncAccountsExist(mContext));
callback.sendSuccess(response);
} else {
callback.sendError("Could not query account existence: unknown kind.");

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

@ -149,10 +149,6 @@ public class RemoteTabsPanel extends HomeFragment {
return null;
}
if (SyncConstants.ACCOUNTTYPE_SYNC.equals(account.type)) {
return Action.None;
}
if (!FxAccountConstants.ACCOUNT_TYPE.equals(account.type)) {
Log.wtf(LOGTAG, "Non Sync, non Firefox Android Account returned by AccountLoader; returning null.");
return null;

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

@ -14,8 +14,8 @@ import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.R;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.RemoteClient;
import org.mozilla.gecko.db.TabsAccessor;
@ -29,9 +29,6 @@ import org.mozilla.gecko.sync.CommandProcessor;
import org.mozilla.gecko.sync.CommandRunner;
import org.mozilla.gecko.sync.GlobalSession;
import org.mozilla.gecko.sync.SyncConfiguration;
import org.mozilla.gecko.sync.SyncConstants;
import org.mozilla.gecko.sync.setup.SyncAccounts;
import org.mozilla.gecko.sync.syncadapter.SyncAdapter;
import java.util.Arrays;
import java.util.Collection;
@ -168,17 +165,6 @@ public class SendTab extends ShareMethod {
return;
}
final Account[] syncAccounts = accountManager.getAccountsByType(SyncConstants.ACCOUNTTYPE_SYNC);
if (syncAccounts.length > 0) {
tabSender = new Sync11TabSender(context, syncAccounts[0], accountManager);
updateClientList(tabSender);
Log.i(LOGTAG, "Allowing tab send for Sync account.");
registerDisplayURICommand();
return;
}
// Have registered UIs offer to set up a Firefox Account.
setOverrideIntentAction(FxAccountConstants.ACTION_FXA_GET_STARTED);
}
@ -308,32 +294,4 @@ public class SendTab extends ShareMethod {
fxAccount.requestSync(FirefoxAccounts.FORCE, STAGES_TO_SYNC, null);
}
}
private static class Sync11TabSender implements TabSender {
private final Account account;
private final AccountManager accountManager;
private final Context context;
private Sync11TabSender(Context aContext, Account syncAccount, AccountManager manager) {
context = aContext;
account = syncAccount;
accountManager = manager;
}
@Override
public String getAccountGUID() {
try {
SharedPreferences prefs = SyncAccounts.blockingPrefsFromDefaultProfileV0(context, accountManager, account);
return prefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null);
} catch (Exception e) {
Log.w(LOGTAG, "Could not get Sync account parameters or preferences; aborting.");
return null;
}
}
@Override
public void sync() {
SyncAdapter.requestImmediateSync(account, STAGES_TO_SYNC);
}
}
}

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

@ -5,14 +5,11 @@
package org.mozilla.gecko.preferences;
import android.accounts.Account;
import android.content.Context;
import android.content.Intent;
import android.preference.Preference;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
@ -22,19 +19,14 @@ import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.TelemetryContract.Method;
import org.mozilla.gecko.fxa.FirefoxAccounts;
import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.activities.FxAccountWebFlowActivity;
import org.mozilla.gecko.fxa.activities.PicassoPreferenceIconTarget;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.sync.ExtendedJSONObject;
import org.mozilla.gecko.sync.setup.SyncAccounts;
import org.mozilla.gecko.sync.setup.activities.SetupSyncActivity;
import org.mozilla.gecko.util.ThreadUtils;
class SyncPreference extends Preference {
private static final boolean DEFAULT_TO_FXA = true;
private final Context mContext;
private final Target profileAvatarTarget;
@ -45,18 +37,6 @@ class SyncPreference extends Preference {
profileAvatarTarget = new PicassoPreferenceIconTarget(mContext.getResources(), this, cornerRadius);
}
private void openSync11Settings() {
// Show Sync setup if no accounts exist; otherwise, show account settings.
if (SyncAccounts.syncAccountsExist(mContext)) {
// We don't check for failure here. If you already have Sync set up,
// then there's nothing we can do.
SyncAccounts.openSyncSettings(mContext);
return;
}
Intent intent = new Intent(mContext, SetupSyncActivity.class);
mContext.startActivity(intent);
}
private void launchFxASetup() {
final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
intent.putExtra(FxAccountWebFlowActivity.EXTRA_ENDPOINT, FxAccountConstants.ENDPOINT_PREFERENCES);
@ -120,23 +100,8 @@ class SyncPreference extends Preference {
@Override
protected void onClick() {
// If we're not defaulting to FxA, just do what we've always done.
if (!DEFAULT_TO_FXA) {
openSync11Settings();
return;
}
// If there's a legacy Sync account (or a pickled one on disk),
// open the settings page.
if (SyncAccounts.syncAccountsExist(mContext)) {
if (SyncAccounts.openSyncSettings(mContext) != null) {
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, Method.SETTINGS, "sync_settings");
return;
}
}
// Otherwise, launch the FxA "Get started" activity, which will
// dispatch to the right location.
// Launch the FxA "Get started" activity, which will dispatch to the
// right location.
launchFxASetup();
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, Method.SETTINGS, "sync_setup");
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше