diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js
index b3f4190b7c43..2bcd5e763570 100644
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -385,7 +385,7 @@ pref("urlclassifier.gethash.timeout_ms", 5000);
pref("urlclassifier.max-complete-age", 2700);
// Tracking protection
-pref("privacy.trackingprotection.enabled", true);
+pref("privacy.trackingprotection.enabled", false);
pref("privacy.trackingprotection.pbmode.enabled", false);
#endif
diff --git a/b2g/chrome/content/settings.js b/b2g/chrome/content/settings.js
index 107544bd0358..ab7074a47544 100644
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -671,6 +671,7 @@ var settingsToObserve = {
'mms.debugging.enabled': false,
'network.debugging.enabled': false,
'privacy.donottrackheader.enabled': false,
+ 'privacy.trackingprotection.enabled': false,
'ril.debugging.enabled': false,
'ril.radio.disabled': false,
'ril.mms.requestReadReport.enabled': {
diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml
index fa381995fd49..75c5a2254157 100644
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml
index e6d93db6e115..bea6be377298 100644
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index 17ed8e3480e2..1c0e119ec32e 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,11 +19,11 @@
-
+
-
-
+
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index b85821e6120e..c3802e1d0f17 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index e07de16b1559..47c0391554ec 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -128,10 +128,10 @@
-
+
-
+
diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml
index 1baf3418253a..5fd56f9f9370 100644
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index 17ed8e3480e2..1c0e119ec32e 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,11 +19,11 @@
-
+
-
-
+
+
diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml
index af584905fa3f..a5147b8177f5 100644
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index a72fcf6cc665..157e873354d0 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
- "git_revision": "60cdaa3d3424db3432dc903e7f9c6c8fa099c06d",
+ "git_revision": "0019347fbaedc9d54f2f3436fff17aeb22968174",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
- "revision": "1de2dfa13b0b91c293111198011353c7bb86242d",
+ "revision": "32ae3240869f21601d31c7f71c4fd09c02239353",
"repo_path": "integration/gaia-central"
}
diff --git a/b2g/config/nexus-4-kk/sources.xml b/b2g/config/nexus-4-kk/sources.xml
index cc6f720cd2d8..c44d56843837 100644
--- a/b2g/config/nexus-4-kk/sources.xml
+++ b/b2g/config/nexus-4-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml
index 671e16d0af60..3fcdf1cf8667 100644
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -18,7 +18,7 @@
-
+
diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml
index 5ae9e0c3c5d5..b220a7edf30a 100644
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -141,7 +141,7 @@
-
+
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index c0e188586d90..052a23c8f02c 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1882,6 +1882,12 @@ pref("browser.tabs.remote.autostart.1", false);
pref("browser.tabs.remote.autostart.2", true);
#endif
+// For the about:tabcrashed page
+pref("browser.tabs.crashReporting.sendReport", true);
+pref("browser.tabs.crashReporting.includeURL", false);
+pref("browser.tabs.crashReporting.emailMe", false);
+pref("browser.tabs.crashReporting.email", "");
+
#ifdef NIGHTLY_BUILD
#ifndef MOZ_MULET
pref("layers.async-pan-zoom.enabled", true);
diff --git a/browser/base/content/aboutTabCrashed.js b/browser/base/content/aboutTabCrashed.js
index a0abedc0e58f..5ff0071a46e2 100644
--- a/browser/base/content/aboutTabCrashed.js
+++ b/browser/base/content/aboutTabCrashed.js
@@ -3,27 +3,66 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
function parseQueryString() {
- let url = document.documentURI;
- let queryString = url.replace(/^about:tabcrashed?e=tabcrashed/, "");
+ let URL = document.documentURI;
+ let queryString = URL.replace(/^about:tabcrashed?e=tabcrashed/, "");
let titleMatch = queryString.match(/d=([^&]*)/);
- return titleMatch && titleMatch[1] ? decodeURIComponent(titleMatch[1]) : "";
+ let URLMatch = queryString.match(/u=([^&]*)/);
+ return {
+ title: titleMatch && titleMatch[1] ? decodeURIComponent(titleMatch[1]) : "",
+ URL: URLMatch && URLMatch[1] ? decodeURIComponent(URLMatch[1]) : "",
+ };
}
-document.title = parseQueryString();
+function displayUI() {
+ if (!hasReport()) {
+ return;
+ }
-function shouldSendReport() {
- if (!document.documentElement.classList.contains("crashDumpAvailable"))
- return false;
- return document.getElementById("sendReport").checked;
+ let sendCrashReport = document.getElementById("sendReport").checked;
+ let container = document.getElementById("crash-reporter-container");
+ container.hidden = !sendCrashReport;
+}
+
+function hasReport() {
+ return document.documentElement.classList.contains("crashDumpAvailable");
}
function sendEvent(message) {
+ let comments = "";
+ let email = "";
+ let URL = "";
+ let sendCrashReport = false;
+ let emailMe = false;
+ let includeURL = false;
+
+ if (hasReport()) {
+ sendCrashReport = document.getElementById("sendReport").checked;
+ if (sendCrashReport) {
+ comments = document.getElementById("comments").value.trim();
+
+ includeURL = document.getElementById("includeURL").checked;
+ if (includeURL) {
+ URL = parseQueryString().URL.trim();
+ }
+
+ emailMe = document.getElementById("emailMe").checked;
+ if (emailMe) {
+ email = document.getElementById("email").value.trim();
+ }
+ }
+ }
+
let event = new CustomEvent("AboutTabCrashedMessage", {
bubbles: true,
detail: {
message,
- sendCrashReport: shouldSendReport(),
+ sendCrashReport,
+ comments,
+ email,
+ emailMe,
+ includeURL,
+ URL,
},
});
@@ -42,6 +81,17 @@ function restoreAll() {
sendEvent("restoreAll");
}
+document.title = parseQueryString().title;
+
// Error pages are loaded as LOAD_BACKGROUND, so they don't get load events.
var event = new CustomEvent("AboutTabCrashedLoad", {bubbles:true});
document.dispatchEvent(event);
+
+addEventListener("DOMContentLoaded", function() {
+ let sendReport = document.getElementById("sendReport");
+ sendReport.addEventListener("click", function() {
+ displayUI();
+ });
+
+ displayUI();
+});
diff --git a/browser/base/content/aboutTabCrashed.xhtml b/browser/base/content/aboutTabCrashed.xhtml
index ec1f37161bf1..9de02cc21029 100644
--- a/browser/base/content/aboutTabCrashed.xhtml
+++ b/browser/base/content/aboutTabCrashed.xhtml
@@ -37,8 +37,22 @@
&tabCrashed.message;
&tabCrashed.reportSent;
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index ed10547395f3..c3e933b338e8 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1166,7 +1166,15 @@ var gBrowserInit = {
let browser = gBrowser.getBrowserForDocument(ownerDoc);
#ifdef MOZ_CRASHREPORTER
if (event.detail.sendCrashReport) {
- TabCrashReporter.submitCrashReport(browser);
+ TabCrashReporter.submitCrashReport(browser, {
+ comments: event.detail.comments,
+ email: event.detail.email,
+ emailMe: event.detail.emailMe,
+ includeURL: event.detail.includeURL,
+ URL: event.detail.URL,
+ });
+ } else {
+ TabCrashReporter.dontSubmitCrashReport();
}
#endif
diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index e2e0b88254b2..7eb4300b733d 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -5355,13 +5355,11 @@
]]>
A%20regular,%20everyday,%20normal%20page.";
+const COMMENTS = "Here's my test comment!";
+const EMAIL = "foo@privacy.com";
+
+/**
+ * For an nsIPropertyBag, returns the value for a given
+ * key.
+ *
+ * @param bag
+ * The nsIPropertyBag to retrieve the value from
+ * @param key
+ * The key that we want to get the value for from the
+ * bag
+ * @returns The value corresponding to the key from the bag,
+ * or null if the value could not be retrieved (for
+ * example, if no value is set at that key).
+*/
+function getPropertyBagValue(bag, key) {
+ try {
+ let val = bag.getProperty(key);
+ return val;
+ } catch(e if e.result == Cr.NS_ERROR_FAILURE) {}
+
+ return null;
+}
+
+/**
+ * Returns a Promise that resolves once a crash report has
+ * been submitted. This function will also test the crash
+ * reports extra data to see if it matches expectedExtra.
+ *
+ * @param expectedExtra
+ * An Object whose key-value pairs will be compared
+ * against the key-value pairs in the extra data of the
+ * crash report. A test failure will occur if there is
+ * a mismatch.
+ *
+ * Note that this will only check the values that exist
+ * in expectedExtra. It's possible that the crash report
+ * will contain other extra information that is not
+ * compared against.
+ * @returns Promise
+ */
+function promiseCrashReport(expectedExtra) {
+ return Task.spawn(function*() {
+ info("Starting wait on crash-report-status");
+ let [subject, data] =
+ yield TestUtils.topicObserved("crash-report-status", (subject, data) => {
+ return data == "success";
+ });
+ info("Topic observed!");
+
+ if (!(subject instanceof Ci.nsIPropertyBag2)) {
+ throw new Error("Subject was not a Ci.nsIPropertyBag2");
+ }
+
+ let remoteID = getPropertyBagValue(subject, "serverCrashID");
+ if (!remoteID) {
+ throw new Error("Report should have a server ID");
+ }
+
+ let file = Cc["@mozilla.org/file/local;1"]
+ .createInstance(Ci.nsILocalFile);
+ file.initWithPath(Services.crashmanager._submittedDumpsDir);
+ file.append(remoteID + ".txt");
+ if (!file.exists()) {
+ throw new Error("Report should have been received by the server");
+ }
+
+ file.remove(false);
+
+ let extra = getPropertyBagValue(subject, "extra");
+ if (!(extra instanceof Ci.nsIPropertyBag2)) {
+ throw new Error("extra was not a Ci.nsIPropertyBag2");
+ }
+
+ info("Iterating crash report extra keys");
+ let enumerator = extra.enumerator;
+ while (enumerator.hasMoreElements()) {
+ let key = enumerator.getNext().QueryInterface(Ci.nsIProperty).name;
+ let value = extra.getPropertyAsAString(key);
+ if (key in expectedExtra) {
+ is(value, expectedExtra[key],
+ `Crash report had the right extra value for ${key}`);
+ }
+ }
+ });
+}
+
+/**
+ * Sets up the browser to send crash reports to the local crash report
+ * testing server.
+ */
+add_task(function* setup() {
+ // The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables crash
+ // reports. This test needs them enabled. The test also needs a mock
+ // report server, and fortunately one is already set up by toolkit/
+ // crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL,
+ // which CrashSubmit.jsm uses as a server override.
+ let env = Cc["@mozilla.org/process/environment;1"]
+ .getService(Components.interfaces.nsIEnvironment);
+ let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
+ let serverUrl = env.get("MOZ_CRASHREPORTER_URL");
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
+ env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
+
+ registerCleanupFunction(function() {
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
+ env.set("MOZ_CRASHREPORTER_URL", serverUrl);
+ });
+});
+
+/**
+ * This function returns a Promise that resolves once the following
+ * actions have taken place:
+ *
+ * 1) A new tab is opened up at PAGE
+ * 2) The tab is crashed
+ * 3) The about:tabcrashed page's fields are set in accordance with
+ * fieldValues
+ * 4) The tab is restored
+ * 5) A crash report is received from the testing server
+ * 6) Any tab crash prefs that were overwritten are reset
+ *
+ * @param fieldValues
+ * An Object describing how to set the about:tabcrashed
+ * fields. The following properties are accepted:
+ *
+ * comments (String)
+ * The comments to put in the comment textarea
+ * email (String)
+ * The email address to put in the email address input
+ * emailMe (bool)
+ * The checked value of the "Email me" checkbox
+ * includeURL (bool)
+ * The checked value of the "Include URL" checkbox
+ *
+ * If any of these fields are missing, the defaults from
+ * the user preferences are used.
+ * @param expectedExtra
+ * An Object describing the expected values that the submitted
+ * crash report's extra data should contain.
+ * @returns Promise
+ */
+function crashTabTestHelper(fieldValues, expectedExtra) {
+ return BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: PAGE,
+ }, function*(browser) {
+ let prefs = TabCrashReporter.prefs;
+ let originalSendReport = prefs.getBoolPref("sendReport");
+ let originalEmailMe = prefs.getBoolPref("emailMe");
+ let originalIncludeURL = prefs.getBoolPref("includeURL");
+ let originalEmail = prefs.getCharPref("email");
+
+ let tab = gBrowser.getTabForBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
+ let doc = browser.contentDocument;
+
+ // Since about:tabcrashed will run in the parent process, we can safely
+ // manipulate its DOM nodes directly
+ let comments = doc.getElementById("comments");
+ let email = doc.getElementById("email");
+ let emailMe = doc.getElementById("emailMe");
+ let includeURL = doc.getElementById("includeURL");
+
+ if (fieldValues.hasOwnProperty("comments")) {
+ comments.value = fieldValues.comments;
+ }
+
+ if (fieldValues.hasOwnProperty("email")) {
+ email.value = fieldValues.email;
+ }
+
+ if (fieldValues.hasOwnProperty("emailMe")) {
+ emailMe.checked = fieldValues.emailMe;
+ }
+
+ if (fieldValues.hasOwnProperty("includeURL")) {
+ includeURL.checked = fieldValues.includeURL;
+ }
+
+ let crashReport = promiseCrashReport(expectedExtra);
+ let restoreTab = browser.contentDocument.getElementById("restoreTab");
+ restoreTab.click();
+ yield BrowserTestUtils.waitForEvent(tab, "SSTabRestored");
+ yield crashReport;
+
+ // Submitting the crash report may have set some prefs regarding how to
+ // send tab crash reports. Let's reset them for the next test.
+ prefs.setBoolPref("sendReport", originalSendReport);
+ prefs.setBoolPref("emailMe", originalEmailMe);
+ prefs.setBoolPref("includeURL", originalIncludeURL);
+ prefs.setCharPref("email", originalEmail);
+ });
+}
+
+/**
+ * Tests what we send with the crash report by default. By default, we do not
+ * send any comments, the URL of the crashing page, or the email address of
+ * the user.
+ */
+add_task(function* test_default() {
+ yield crashTabTestHelper({}, {
+ "Comments": "",
+ "URL": "",
+ "Email": "",
+ });
+});
+
+/**
+ * Test just sending a comment.
+ */
+add_task(function* test_just_a_comment() {
+ yield crashTabTestHelper({
+ comments: COMMENTS,
+ }, {
+ "Comments": COMMENTS,
+ "URL": "",
+ "Email": "",
+ });
+});
+
+/**
+ * Test that we don't send email if emailMe is unchecked
+ */
+add_task(function* test_no_email() {
+ yield crashTabTestHelper({
+ email: EMAIL,
+ emailMe: false,
+ }, {
+ "Comments": "",
+ "URL": "",
+ "Email": "",
+ });
+});
+
+/**
+ * Test that we can send an email address if emailMe is checked
+ */
+add_task(function* test_yes_email() {
+ yield crashTabTestHelper({
+ email: EMAIL,
+ emailMe: true,
+ }, {
+ "Comments": "",
+ "URL": "",
+ "Email": EMAIL,
+ });
+});
+
+/**
+ * Test that we will send the URL of the page if includeURL is checked.
+ */
+add_task(function* test_send_URL() {
+ yield crashTabTestHelper({
+ includeURL: true,
+ }, {
+ "Comments": "",
+ "URL": PAGE,
+ "Email": "",
+ });
+});
+
+/**
+ * Test that we can send comments, the email address, and the URL
+ */
+add_task(function* test_send_all() {
+ yield crashTabTestHelper({
+ includeURL: true,
+ emailMe: true,
+ email: EMAIL,
+ comments: COMMENTS,
+ }, {
+ "Comments": COMMENTS,
+ "URL": PAGE,
+ "Email": EMAIL,
+ });
+});
+
+/**
+ * Test that if we have an email address stored in prefs, and we decide
+ * not to submit the email address in the next crash report, that we
+ * clear the email address.
+ */
+add_task(function* test_clear_email() {
+ return BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: PAGE,
+ }, function*(browser) {
+ let prefs = TabCrashReporter.prefs;
+ let originalSendReport = prefs.getBoolPref("sendReport");
+ let originalEmailMe = prefs.getBoolPref("emailMe");
+ let originalIncludeURL = prefs.getBoolPref("includeURL");
+ let originalEmail = prefs.getCharPref("email");
+
+ // Pretend that we stored an email address from the previous
+ // crash
+ prefs.setCharPref("email", EMAIL);
+ prefs.setBoolPref("emailMe", true);
+
+ let tab = gBrowser.getTabForBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
+ let doc = browser.contentDocument;
+
+ // Since about:tabcrashed will run in the parent process, we can safely
+ // manipulate its DOM nodes directly
+ let emailMe = doc.getElementById("emailMe");
+ emailMe.checked = false;
+
+ let crashReport = promiseCrashReport({
+ Email: "",
+ });
+
+ let restoreTab = browser.contentDocument.getElementById("restoreTab");
+ restoreTab.click();
+ yield BrowserTestUtils.waitForEvent(tab, "SSTabRestored");
+ yield crashReport;
+
+ is(prefs.getCharPref("email"), "", "No email address should be stored");
+
+ // Submitting the crash report may have set some prefs regarding how to
+ // send tab crash reports. Let's reset them for the next test.
+ prefs.setBoolPref("sendReport", originalSendReport);
+ prefs.setBoolPref("emailMe", originalEmailMe);
+ prefs.setBoolPref("includeURL", originalIncludeURL);
+ prefs.setCharPref("email", originalEmail);
+ });
+});
diff --git a/browser/components/loop/content/shared/js/views.js b/browser/components/loop/content/shared/js/views.js
index b6d4e1899af4..ddb45e5d2baf 100644
--- a/browser/components/loop/content/shared/js/views.js
+++ b/browser/components/loop/content/shared/js/views.js
@@ -120,10 +120,12 @@ loop.shared.views = (function(_, mozL10n) {
_handleShareTabs: function() {
this._startScreenShare("browser");
+ this.hideDropdownMenu();
},
_handleShareWindows: function() {
this._startScreenShare("window");
+ this.hideDropdownMenu();
},
_getTitle: function() {
diff --git a/browser/components/loop/content/shared/js/views.jsx b/browser/components/loop/content/shared/js/views.jsx
index c58ef9f3f9c0..9b61b39a0082 100644
--- a/browser/components/loop/content/shared/js/views.jsx
+++ b/browser/components/loop/content/shared/js/views.jsx
@@ -120,10 +120,12 @@ loop.shared.views = (function(_, mozL10n) {
_handleShareTabs: function() {
this._startScreenShare("browser");
+ this.hideDropdownMenu();
},
_handleShareWindows: function() {
this._startScreenShare("window");
+ this.hideDropdownMenu();
},
_getTitle: function() {
diff --git a/browser/components/loop/test/shared/views_test.js b/browser/components/loop/test/shared/views_test.js
index ac44e4be118a..ebac00ac34de 100644
--- a/browser/components/loop/test/shared/views_test.js
+++ b/browser/components/loop/test/shared/views_test.js
@@ -176,6 +176,22 @@ describe("loop.shared.views", function() {
new sharedActions.StartScreenShare({ type: "browser" }));
});
+ it("should close the dropdown on 'browser' option click", function() {
+ var comp = TestUtils.renderIntoDocument(
+ React.createElement(sharedViews.ScreenShareControlButton, {
+ dispatcher: dispatcher,
+ visible: true,
+ state: SCREEN_SHARE_STATES.INACTIVE
+ }));
+
+ sandbox.stub(comp, "hideDropdownMenu");
+
+ TestUtils.Simulate.click(comp.getDOMNode().querySelector(
+ ".screen-share-menu > li"));
+
+ sinon.assert.calledOnce(comp.hideDropdownMenu);
+ });
+
it("should dispatch a 'window' StartScreenShare action on option click",
function() {
var comp = TestUtils.renderIntoDocument(
@@ -193,6 +209,22 @@ describe("loop.shared.views", function() {
new sharedActions.StartScreenShare({ type: "window" }));
});
+ it("should close the dropdown on 'window' option click", function() {
+ var comp = TestUtils.renderIntoDocument(
+ React.createElement(sharedViews.ScreenShareControlButton, {
+ dispatcher: dispatcher,
+ visible: true,
+ state: SCREEN_SHARE_STATES.INACTIVE
+ }));
+
+ sandbox.stub(comp, "hideDropdownMenu");
+
+ TestUtils.Simulate.click(comp.getDOMNode().querySelector(
+ ".screen-share-menu > li:last-child"));
+
+ sinon.assert.calledOnce(comp.hideDropdownMenu);
+ });
+
it("should have the 'window' option enabled", function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
diff --git a/browser/components/sessionstore/test/browser_async_flushes.js b/browser/components/sessionstore/test/browser_async_flushes.js
index f5496e9e60e3..fe6e5b639ffd 100644
--- a/browser/components/sessionstore/test/browser_async_flushes.js
+++ b/browser/components/sessionstore/test/browser_async_flushes.js
@@ -69,7 +69,7 @@ add_task(function* test_crash() {
// the content process. The "crash" message makes it first so that we don't
// get a chance to process the flush. The TabStateFlusher however should be
// notified so that the flush still completes.
- let promise1 = crashBrowser(browser);
+ let promise1 = BrowserTestUtils.crashBrowser(browser);
let promise2 = TabStateFlusher.flush(browser);
yield Promise.all([promise1, promise2]);
diff --git a/browser/components/sessionstore/test/browser_crashedTabs.js b/browser/components/sessionstore/test/browser_crashedTabs.js
index 71eca9e0baa4..72df2d2a6c45 100644
--- a/browser/components/sessionstore/test/browser_crashedTabs.js
+++ b/browser/components/sessionstore/test/browser_crashedTabs.js
@@ -117,7 +117,7 @@ add_task(function test_crash_page_not_in_history() {
yield TabStateFlusher.flush(browser);
// Crash the tab
- yield crashBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
// Check the tab state and make sure the tab crashed page isn't
// mentioned.
@@ -146,7 +146,7 @@ add_task(function test_revived_history_from_remote() {
yield TabStateFlusher.flush(browser);
// Crash the tab
- yield crashBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
// Browse to a new site that will cause the browser to
// become remote again.
@@ -185,7 +185,7 @@ add_task(function test_revived_history_from_non_remote() {
yield TabStateFlusher.flush(browser);
// Crash the tab
- yield crashBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
// Browse to a new site that will not cause the browser to
// become remote again.
@@ -235,7 +235,7 @@ add_task(function test_revive_tab_from_session_store() {
yield TabStateFlusher.flush(browser);
// Crash the tab
- yield crashBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
is(newTab2.getAttribute("crashed"), "true", "Second tab should be crashed too.");
// Use SessionStore to revive the tab
@@ -286,7 +286,7 @@ add_task(function test_revive_all_tabs_from_session_store() {
yield TabStateFlusher.flush(browser2);
// Crash the tab
- yield crashBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
is(newTab2.getAttribute("crashed"), "true", "Second tab should be crashed too.");
// Use SessionStore to revive all the tabs
@@ -331,7 +331,7 @@ add_task(function test_close_tab_after_crash() {
yield TabStateFlusher.flush(browser);
// Crash the tab
- yield crashBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
let promise = promiseEvent(gBrowser.tabContainer, "TabClose");
@@ -359,7 +359,7 @@ add_task(function* test_hide_restore_all_button() {
yield TabStateFlusher.flush(browser);
// Crash the tab
- yield crashBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
let doc = browser.contentDocument;
let restoreAllButton = doc.getElementById("restoreAll");
@@ -375,7 +375,7 @@ add_task(function* test_hide_restore_all_button() {
yield promiseBrowserLoaded(browser);
// Crash the tab
- yield crashBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
doc = browser.contentDocument;
restoreAllButton = doc.getElementById("restoreAll");
@@ -405,7 +405,7 @@ add_task(function* test_aboutcrashedtabzoom() {
yield TabStateFlusher.flush(browser);
// Crash the tab
- yield crashBrowser(browser);
+ yield BrowserTestUtils.crashBrowser(browser);
ok(ZoomManager.getZoomForBrowser(browser) === 1, "zoom should have reset on crash");
diff --git a/browser/components/sessionstore/test/head.js b/browser/components/sessionstore/test/head.js
index da4c0328ee0c..af326cc7c704 100644
--- a/browser/components/sessionstore/test/head.js
+++ b/browser/components/sessionstore/test/head.js
@@ -538,112 +538,6 @@ function promiseRemoveTab(tab) {
return BrowserTestUtils.removeTab(tab);
}
-/**
- * Returns a Promise that resolves once a remote has experienced
- * a crash. Also does the job of cleaning up the minidump of the crash.
- *
- * @param browser
- * The that will crash
- * @return Promise
- */
-function crashBrowser(browser) {
- /**
- * Returns the directory where crash dumps are stored.
- *
- * @return nsIFile
- */
- function getMinidumpDirectory() {
- let dir = Services.dirsvc.get('ProfD', Ci.nsIFile);
- dir.append("minidumps");
- return dir;
- }
-
- /**
- * Removes a file from a directory. This is a no-op if the file does not
- * exist.
- *
- * @param directory
- * The nsIFile representing the directory to remove from.
- * @param filename
- * A string for the file to remove from the directory.
- */
- function removeFile(directory, filename) {
- let file = directory.clone();
- file.append(filename);
- if (file.exists()) {
- file.remove(false);
- }
- }
-
- // This frame script is injected into the remote browser, and used to
- // intentionally crash the tab. We crash by using js-ctypes and dereferencing
- // a bad pointer. The crash should happen immediately upon loading this
- // frame script.
- let frame_script = () => {
- const Cu = Components.utils;
- Cu.import("resource://gre/modules/ctypes.jsm");
-
- let dies = function() {
- privateNoteIntentionalCrash();
- let zero = new ctypes.intptr_t(8);
- let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
- badptr.contents
- };
-
- dump("Et tu, Brute?");
- dies();
- }
-
- let crashCleanupPromise = new Promise((resolve, reject) => {
- let observer = (subject, topic, data) => {
- is(topic, 'ipc:content-shutdown', 'Received correct observer topic.');
- ok(subject instanceof Ci.nsIPropertyBag2,
- 'Subject implements nsIPropertyBag2.');
- // we might see this called as the process terminates due to previous tests.
- // We are only looking for "abnormal" exits...
- if (!subject.hasKey("abnormal")) {
- info("This is a normal termination and isn't the one we are looking for...");
- return;
- }
-
- let dumpID;
- if ('nsICrashReporter' in Ci) {
- dumpID = subject.getPropertyAsAString('dumpID');
- ok(dumpID, "dumpID is present and not an empty string");
- }
-
- if (dumpID) {
- let minidumpDirectory = getMinidumpDirectory();
- removeFile(minidumpDirectory, dumpID + '.dmp');
- removeFile(minidumpDirectory, dumpID + '.extra');
- }
-
- Services.obs.removeObserver(observer, 'ipc:content-shutdown');
- info("Crash cleaned up");
- resolve();
- };
-
- Services.obs.addObserver(observer, 'ipc:content-shutdown');
- });
-
- let aboutTabCrashedLoadPromise = new Promise((resolve, reject) => {
- browser.addEventListener("AboutTabCrashedLoad", function onCrash() {
- browser.removeEventListener("AboutTabCrashedLoad", onCrash, false);
- info("about:tabcrashed loaded");
- resolve();
- }, false, true);
- });
-
- // This frame script will crash the remote browser as soon as it is
- // evaluated.
- let mm = browser.messageManager;
- mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", false);
- return Promise.all([crashCleanupPromise, aboutTabCrashedLoadPromise]).then(() => {
- let tab = gBrowser.getTabForBrowser(browser);
- is(tab.getAttribute("crashed"), "true", "Tab should be marked as crashed");
- });
-}
-
// Write DOMSessionStorage data to the given browser.
function modifySessionStorage(browser, data, options = {}) {
return ContentTask.spawn(browser, [data, options], function* ([data, options]) {
diff --git a/browser/locales/en-US/chrome/browser/aboutTabCrashed.dtd b/browser/locales/en-US/chrome/browser/aboutTabCrashed.dtd
index 609e001989e4..eac62d7211f9 100644
--- a/browser/locales/en-US/chrome/browser/aboutTabCrashed.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutTabCrashed.dtd
@@ -5,6 +5,11 @@
+
+
+
+
+
diff --git a/browser/modules/ContentCrashReporters.jsm b/browser/modules/ContentCrashReporters.jsm
index 34a1bd75b74f..7c43d9fbb201 100644
--- a/browser/modules/ContentCrashReporters.jsm
+++ b/browser/modules/ContentCrashReporters.jsm
@@ -17,6 +17,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
"resource://gre/modules/CrashSubmit.jsm");
this.TabCrashReporter = {
+ get prefs() {
+ delete this.prefs;
+ return this.prefs = Services.prefs.getBranch("browser.tabs.crashReporting.");
+ },
+
init: function () {
if (this.initialized)
return;
@@ -47,21 +52,66 @@ this.TabCrashReporter = {
if (!browser)
return;
- this.browserMap.set(browser, aSubject.childID);
+ this.browserMap.set(browser.permanentKey, aSubject.childID);
break;
}
},
- submitCrashReport: function (aBrowser) {
- let childID = this.browserMap.get(aBrowser);
+ /**
+ * Submits a crash report from about:tabcrashed
+ *
+ * @param aBrowser
+ * The that the report was sent from.
+ * @param aFormData
+ * An Object with the following properties:
+ *
+ * includeURL (bool):
+ * Whether to include the URL that the user was on
+ * in the crashed tab before the crash occurred.
+ * URL (String)
+ * The URL that the user was on in the crashed tab
+ * before the crash occurred.
+ * emailMe (bool):
+ * Whether or not to include the user's email address
+ * in the crash report.
+ * email (String):
+ * The email address of the user.
+ * comments (String):
+ * Any additional comments from the user.
+ *
+ * Note that it is expected that all properties are set,
+ * even if they are empty.
+ */
+ submitCrashReport: function (aBrowser, aFormData) {
+ let childID = this.browserMap.get(aBrowser.permanentKey);
let dumpID = this.childMap.get(childID);
if (!dumpID)
return
- if (CrashSubmit.submit(dumpID, { recordSubmission: true })) {
- this.childMap.set(childID, null); // Avoid resubmission.
- this.removeSubmitCheckboxesForSameCrash(childID);
+ CrashSubmit.submit(dumpID, {
+ recordSubmission: true,
+ extraExtraKeyVals: {
+ Comments: aFormData.comments,
+ Email: aFormData.email,
+ URL: aFormData.URL,
+ },
+ }).then(null, Cu.reportError);
+
+ this.prefs.setBoolPref("sendReport", true);
+ this.prefs.setBoolPref("includeURL", aFormData.includeURL);
+ this.prefs.setBoolPref("emailMe", aFormData.emailMe);
+ if (aFormData.emailMe) {
+ this.prefs.setCharPref("email", aFormData.email);
+ } else {
+ this.prefs.setCharPref("email", "");
}
+
+ this.childMap.set(childID, null); // Avoid resubmission.
+ this.removeSubmitCheckboxesForSameCrash(childID);
+ },
+
+ dontSubmitCrashReport: function() {
+ this.prefs.setBoolPref("sendReport", false);
},
removeSubmitCheckboxesForSameCrash: function(childID) {
@@ -79,8 +129,8 @@ this.TabCrashReporter = {
if (!doc.documentURI.startsWith("about:tabcrashed"))
continue;
- if (this.browserMap.get(browser) == childID) {
- this.browserMap.delete(browser);
+ if (this.browserMap.get(browser.permanentKey) == childID) {
+ this.browserMap.delete(browser.permanentKey);
browser.contentDocument.documentElement.classList.remove("crashDumpAvailable");
browser.contentDocument.documentElement.classList.add("crashDumpSubmitted");
}
@@ -97,11 +147,27 @@ this.TabCrashReporter = {
if (!this.childMap)
return;
- let dumpID = this.childMap.get(this.browserMap.get(aBrowser));
+ let dumpID = this.childMap.get(this.browserMap.get(aBrowser.permanentKey));
if (!dumpID)
return;
- aBrowser.contentDocument.documentElement.classList.add("crashDumpAvailable");
+ let doc = aBrowser.contentDocument;
+
+ doc.documentElement.classList.add("crashDumpAvailable");
+
+ let sendReport = this.prefs.getBoolPref("sendReport");
+ doc.getElementById("sendReport").checked = sendReport;
+
+ let includeURL = this.prefs.getBoolPref("includeURL");
+ doc.getElementById("includeURL").checked = includeURL;
+
+ let emailMe = this.prefs.getBoolPref("emailMe");
+ doc.getElementById("emailMe").checked = emailMe;
+
+ if (emailMe) {
+ let email = this.prefs.getCharPref("email", "");
+ doc.getElementById("email").value = email;
+ }
},
hideRestoreAllButton: function (aBrowser) {
diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css
index 3836d05f2758..78f56e19cf9f 100644
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -98,12 +98,6 @@
-moz-appearance: -moz-window-titlebar;
}
-@media (-moz-mac-yosemite-theme) {
- #main-window:not(:-moz-lwtheme) > #titlebar {
- -moz-appearance: -moz-mac-vibrancy-light;
- }
-}
-
#main-window:not([tabsintitlebar]) > #titlebar {
height: 22px; /* The native titlebar on OS X is 22px tall. */
}
diff --git a/browser/themes/shared/aboutTabCrashed.css b/browser/themes/shared/aboutTabCrashed.css
index 2ef767eb8b24..e42922ac95d6 100644
--- a/browser/themes/shared/aboutTabCrashed.css
+++ b/browser/themes/shared/aboutTabCrashed.css
@@ -9,3 +9,34 @@
#reportSent {
font-weight: bold;
}
+
+#crash-reporter-container {
+ width: 80%;
+ background-color: var(--in-content-box-background-hover);
+ margin: 24px 0;
+ padding: 14px;
+ border: 1px solid var(--in-content-box-border-color);
+ border-radius: 2px;
+}
+
+#crash-reporter-title {
+ font-weight: bold;
+ margin: 0 0 14px 0;
+}
+
+input[type="text"],
+textarea {
+ width: 100%;
+ box-sizing: border-box;
+ resize: none;
+}
+
+#options {
+ list-style: none;
+ margin-inline-start: 0;
+}
+
+input[type="text"],
+#options > li {
+ margin: 14px 0 0 0;
+}
diff --git a/browser/themes/shared/incontentprefs/preferences.inc.css b/browser/themes/shared/incontentprefs/preferences.inc.css
index de70f654676e..ac431b28fac5 100644
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -589,6 +589,7 @@ description > html|a {
}
.fxaAccountBoxButtons > button {
+ text-align: center;
padding-left: 11px;
padding-right: 11px;
margin: 0;
diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css
index 5337061cd798..cea8a568d71a 100644
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -2013,7 +2013,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
}
:root {
- --tab-toolbar-navbar-overlap: 0;
+ --tab-toolbar-navbar-overlap: 0px;
}
#nav-bar {
diff --git a/browser/themes/windows/customizableui/panelUIOverlay.css b/browser/themes/windows/customizableui/panelUIOverlay.css
index 2f5c86c2bfaf..a2c59cb88990 100644
--- a/browser/themes/windows/customizableui/panelUIOverlay.css
+++ b/browser/themes/windows/customizableui/panelUIOverlay.css
@@ -223,9 +223,7 @@ menu.subviewbutton > .menu-right:-moz-locale-dir(rtl) {
}
#BMB_bookmarksPopup menupopup[placespopup=true] > hbox {
- /* After fixing of bug 1194480 the box-shadow can be removed again */
- /* box-shadow: none; */
- box-shadow: 0 0 4px rgba(0,0,0,0.02);
+ box-shadow: none;
background: -moz-field;
border: 1px solid ThreeDShadow;
}
diff --git a/devtools/client/debugger/test/mochitest/browser.ini b/devtools/client/debugger/test/mochitest/browser.ini
index 99b1bb038945..4c4749726355 100644
--- a/devtools/client/debugger/test/mochitest/browser.ini
+++ b/devtools/client/debugger/test/mochitest/browser.ini
@@ -567,6 +567,8 @@ skip-if = e10s && debug
skip-if = e10s && debug
[browser_dbg_watch-expressions-02.js]
skip-if = e10s && debug
+[browser_dbg_worker-window.js]
+skip-if = e10s && debug
[browser_dbg_WorkerActor.attach.js]
skip-if = e10s && debug
[browser_dbg_WorkerActor.attachThread.js]
diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_worker-window.js b/devtools/client/debugger/test/mochitest/browser_dbg_worker-window.js
new file mode 100644
index 000000000000..5558f2ab8f29
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_worker-window.js
@@ -0,0 +1,43 @@
+// Check to make sure that a worker can be attached to a toolbox
+// directly, and that the toolbox has expected properties.
+
+var TAB_URL = EXAMPLE_URL + "doc_WorkerActor.attachThread-tab.html";
+var WORKER_URL = "code_WorkerActor.attachThread-worker.js";
+
+add_task(function* () {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+
+ let client = new DebuggerClient(DebuggerServer.connectPipe());
+ yield connect(client);
+
+ let tab = yield addTab(TAB_URL);
+ let { tabs } = yield listTabs(client);
+ let [, tabClient] = yield attachTab(client, findTab(tabs, TAB_URL));
+
+ yield listWorkers(tabClient);
+ yield createWorkerInTab(tab, WORKER_URL);
+
+ let { workers } = yield listWorkers(tabClient);
+ let [, workerClient] = yield attachWorker(tabClient,
+ findWorker(workers, WORKER_URL));
+
+ let toolbox = yield gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
+ "jsdebugger",
+ Toolbox.HostType.WINDOW);
+
+ is(toolbox._host.type, "window", "correct host");
+ ok(toolbox._host._window.document.title.contains(WORKER_URL),
+ "worker URL in host title");
+
+ let toolTabs = toolbox.doc.querySelectorAll(".devtools-tab");
+ let activeTools = [...toolTabs].map(tab=>tab.getAttribute("toolid"));
+
+ is(activeTools.join(","), "webconsole,jsdebugger,scratchpad,options",
+ "Correct set of tools supported by worker");
+
+ yield gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
+ terminateWorkerInTab(tab, WORKER_URL);
+ yield waitForWorkerClose(workerClient);
+ yield close(client);
+});
diff --git a/devtools/client/framework/target.js b/devtools/client/framework/target.js
index 2ffd2f9e0397..e0694c188958 100644
--- a/devtools/client/framework/target.js
+++ b/devtools/client/framework/target.js
@@ -856,6 +856,10 @@ WorkerTarget.prototype = {
return true;
},
+ get url() {
+ return this._workerClient.url;
+ },
+
get form() {
return {
from: this._workerClient.actor,
diff --git a/devtools/client/framework/toolbox.js b/devtools/client/framework/toolbox.js
index 067f4dfc2cee..07696d35a678 100644
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -1493,10 +1493,8 @@ Toolbox.prototype = {
toolName = toolboxStrings("toolbox.defaultTitle");
}
let title = toolboxStrings("toolbox.titleTemplate",
- toolName,
- this.target.isAddon ?
- this.target.name :
- this.target.url || this.target.name);
+ toolName, this.target.name ||
+ this.target.url);
this._host.setTitle(title);
},
diff --git a/devtools/client/styleinspector/rule-view.js b/devtools/client/styleinspector/rule-view.js
index f0740eed767c..5253d0228229 100644
--- a/devtools/client/styleinspector/rule-view.js
+++ b/devtools/client/styleinspector/rule-view.js
@@ -26,6 +26,7 @@ const {
throttle
} = require("devtools/client/styleinspector/utils");
const {
+ escapeCSSComment,
parseDeclarations,
parseSingleValue,
parsePseudoClassesAndAttributes,
@@ -1117,7 +1118,7 @@ TextProperty.prototype = {
// Comment out property declarations that are not enabled
if (!this.enabled) {
- declaration = "/* " + declaration + " */";
+ declaration = "/* " + escapeCSSComment(declaration) + " */";
}
return declaration;
diff --git a/devtools/client/styleinspector/test/browser_ruleview_copy_styles.js b/devtools/client/styleinspector/test/browser_ruleview_copy_styles.js
index cac459e4bc30..f081d26ce52d 100644
--- a/devtools/client/styleinspector/test/browser_ruleview_copy_styles.js
+++ b/devtools/client/styleinspector/test/browser_ruleview_copy_styles.js
@@ -103,6 +103,7 @@ add_task(function*() {
"\tbackground-color: #00F;[\\r\\n]+" +
"\tfont-size: 12px;[\\r\\n]+" +
"\tborder-color: #00F !important;[\\r\\n]+" +
+ "\t--var: \"\\*/\";[\\r\\n]+" +
"}",
hidden: {
copyLocation: true,
@@ -144,7 +145,7 @@ add_task(function*() {
},
{
setup: function*() {
- yield disableProperty(view);
+ yield disableProperty(view, 0);
},
desc: "Test Copy Rule with Disabled Property",
node: ruleEditor.rule.textProps[2].editor.nameSpan,
@@ -154,6 +155,30 @@ add_task(function*() {
"\tbackground-color: #00F;[\\r\\n]+" +
"\tfont-size: 12px;[\\r\\n]+" +
"\tborder-color: #00F !important;[\\r\\n]+" +
+ "\t--var: \"\\*/\";[\\r\\n]+" +
+ "}",
+ hidden: {
+ copyLocation: true,
+ copyPropertyDeclaration: false,
+ copyPropertyName: false,
+ copyPropertyValue: true,
+ copySelector: true,
+ copyRule: false
+ }
+ },
+ {
+ setup: function*() {
+ yield disableProperty(view, 4);
+ },
+ desc: "Test Copy Rule with Disabled Property with Comment",
+ node: ruleEditor.rule.textProps[2].editor.nameSpan,
+ menuItem: contextmenu.menuitemCopyRule,
+ expectedPattern: "#testid {[\\r\\n]+" +
+ "\t\/\\* color: #F00; \\*\/[\\r\\n]+" +
+ "\tbackground-color: #00F;[\\r\\n]+" +
+ "\tfont-size: 12px;[\\r\\n]+" +
+ "\tborder-color: #00F !important;[\\r\\n]+" +
+ "\t/\\* --var: \"\\*\\\\\/\"; \\*\/[\\r\\n]+" +
"}",
hidden: {
copyLocation: true,
@@ -241,9 +266,9 @@ function* checkCopyStyle(view, node, menuItem, expectedPattern, hidden) {
view._contextmenu._menupopup.hidePopup();
}
-function* disableProperty(view) {
+function* disableProperty(view, index) {
let ruleEditor = getRuleViewRuleEditor(view, 1);
- let propEditor = ruleEditor.rule.textProps[0].editor;
+ let propEditor = ruleEditor.rule.textProps[index].editor;
info("Disabling a property");
propEditor.enable.click();
diff --git a/devtools/client/styleinspector/test/doc_copystyles.css b/devtools/client/styleinspector/test/doc_copystyles.css
index 7494c11a6fce..83f0c87b1262 100644
--- a/devtools/client/styleinspector/test/doc_copystyles.css
+++ b/devtools/client/styleinspector/test/doc_copystyles.css
@@ -7,4 +7,5 @@ html, body, #testid {
background-color: #00F;
font-size: 12px;
border-color: #00F !important;
+ --var: "*/";
}
diff --git a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp b/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
index b9cabe1b641b..3296823b83ad 100644
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
@@ -86,11 +86,11 @@ AvStatusToSinkString(BluetoothA2dpConnectionState aState, nsAString& aString)
}
}
-class BluetoothA2dpManager::InitA2dpResultHandler final
+class BluetoothA2dpManager::InitResultHandler final
: public BluetoothA2dpResultHandler
{
public:
- InitA2dpResultHandler(BluetoothProfileResultHandler* aRes)
+ InitResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
@@ -172,7 +172,7 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
}
BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
- sBtA2dpInterface->Init(a2dpManager, new InitA2dpResultHandler(aRes));
+ sBtA2dpInterface->Init(a2dpManager, new InitResultHandler(aRes));
}
BluetoothA2dpManager::~BluetoothA2dpManager()
@@ -227,11 +227,11 @@ BluetoothA2dpManager::Get()
return sBluetoothA2dpManager;
}
-class BluetoothA2dpManager::CleanupA2dpResultHandler final
+class BluetoothA2dpManager::CleanupResultHandler final
: public BluetoothA2dpResultHandler
{
public:
- CleanupA2dpResultHandler(BluetoothProfileResultHandler* aRes)
+ CleanupResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
@@ -260,11 +260,11 @@ private:
nsRefPtr mRes;
};
-class BluetoothA2dpManager::CleanupA2dpResultHandlerRunnable final
+class BluetoothA2dpManager::CleanupResultHandlerRunnable final
: public nsRunnable
{
public:
- CleanupA2dpResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
+ CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
@@ -289,11 +289,11 @@ BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
MOZ_ASSERT(NS_IsMainThread());
if (sBtA2dpInterface) {
- sBtA2dpInterface->Cleanup(new CleanupA2dpResultHandler(aRes));
+ sBtA2dpInterface->Cleanup(new CleanupResultHandler(aRes));
} else if (aRes) {
// We dispatch a runnable here to make the profile resource handler
// behave as if A2DP was initialized.
- nsRefPtr r = new CleanupA2dpResultHandlerRunnable(aRes);
+ nsRefPtr r = new CleanupResultHandlerRunnable(aRes);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
}
diff --git a/dom/bluetooth/bluedroid/BluetoothA2dpManager.h b/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
index f4ac3cd41d67..44a4bb355149 100644
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
@@ -47,11 +47,11 @@ protected:
virtual ~BluetoothA2dpManager();
private:
- class CleanupA2dpResultHandler;
- class CleanupA2dpResultHandlerRunnable;
+ class CleanupResultHandler;
+ class CleanupResultHandlerRunnable;
class ConnectResultHandler;
class DisconnectResultHandler;
- class InitA2dpResultHandler;
+ class InitResultHandler;
class OnErrorProfileResultHandlerRunnable;
BluetoothA2dpManager();
diff --git a/dom/bluetooth/bluedroid/BluetoothAvrcpManager.cpp b/dom/bluetooth/bluedroid/BluetoothAvrcpManager.cpp
index 7b36f29813d8..461968cac8db 100644
--- a/dom/bluetooth/bluedroid/BluetoothAvrcpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothAvrcpManager.cpp
@@ -118,11 +118,11 @@ BluetoothAvrcpManager::Reset()
mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
}
-class BluetoothAvrcpManager::InitAvrcpResultHandler final
+class BluetoothAvrcpManager::InitResultHandler final
: public BluetoothAvrcpResultHandler
{
public:
- InitAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
+ InitResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
@@ -209,7 +209,7 @@ BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
}
BluetoothAvrcpManager* avrcpManager = BluetoothAvrcpManager::Get();
- sBtAvrcpInterface->Init(avrcpManager, new InitAvrcpResultHandler(aRes));
+ sBtAvrcpInterface->Init(avrcpManager, new InitResultHandler(aRes));
}
BluetoothAvrcpManager::~BluetoothAvrcpManager()
@@ -245,11 +245,11 @@ BluetoothAvrcpManager::Get()
return sBluetoothAvrcpManager;
}
-class BluetoothAvrcpManager::CleanupAvrcpResultHandler final
+class BluetoothAvrcpManager::CleanupResultHandler final
: public BluetoothAvrcpResultHandler
{
public:
- CleanupAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
+ CleanupResultHandler(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
{ }
@@ -285,25 +285,19 @@ private:
nsRefPtr mRes;
};
-class BluetoothAvrcpManager::CleanupAvrcpResultHandlerRunnable final
+class BluetoothAvrcpManager::CleanupResultHandlerRunnable final
: public nsRunnable
{
public:
- CleanupAvrcpResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
+ CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
: mRes(aRes)
- { }
+ {
+ MOZ_ASSERT(mRes);
+ }
NS_IMETHOD Run() override
{
- sBtAvrcpInterface = nullptr;
- if (sBtAvrcpInterface) {
- sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
- } else if (mRes) {
- /* Not all backends support AVRCP. If it's not available
- * we signal success from here.
- */
- mRes->Deinit();
- }
+ mRes->Deinit();
return NS_OK;
}
@@ -319,11 +313,11 @@ BluetoothAvrcpManager::DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes)
MOZ_ASSERT(NS_IsMainThread());
if (sBtAvrcpInterface) {
- sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(aRes));
+ sBtAvrcpInterface->Cleanup(new CleanupResultHandler(aRes));
} else if (aRes) {
// We dispatch a runnable here to make the profile resource handler
- // behave as if A2DP was initialized.
- nsRefPtr r = new CleanupAvrcpResultHandlerRunnable(aRes);
+ // behave as if AVRCP was initialized.
+ nsRefPtr r = new CleanupResultHandlerRunnable(aRes);
if (NS_FAILED(NS_DispatchToMainThread(r))) {
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
}
diff --git a/dom/bluetooth/bluedroid/BluetoothAvrcpManager.h b/dom/bluetooth/bluedroid/BluetoothAvrcpManager.h
index 3be51ab1dddd..a4bc1913c291 100644
--- a/dom/bluetooth/bluedroid/BluetoothAvrcpManager.h
+++ b/dom/bluetooth/bluedroid/BluetoothAvrcpManager.h
@@ -60,11 +60,11 @@ protected:
virtual ~BluetoothAvrcpManager();
private:
- class CleanupAvrcpResultHandler;
- class CleanupAvrcpResultHandlerRunnable;
+ class CleanupResultHandler;
+ class CleanupResultHandlerRunnable;
class ConnectRunnable;
class DisconnectRunnable;
- class InitAvrcpResultHandler;
+ class InitResultHandler;
class OnErrorProfileResultHandlerRunnable;
BluetoothAvrcpManager();
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.cpp
index d73b7344f741..c536bc31f9c9 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.cpp
@@ -170,129 +170,31 @@ public:
}
};
-// Init operator class for ConnectionStateNotification
-class BluetoothDaemonA2dpModule::ConnectionStateInitOp final
- : private PDUInitOp
-{
-public:
- ConnectionStateInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (BluetoothA2dpConnectionState& aArg1,
- BluetoothAddress& aArg2) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read state */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read address */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonA2dpModule::ConnectionStateNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
ConnectionStateNotification::Dispatch(
&BluetoothA2dpNotificationHandler::ConnectionStateNotification,
- ConnectionStateInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
-// Init operator class for AudioStateNotification
-class BluetoothDaemonA2dpModule::AudioStateInitOp final
- : private PDUInitOp
-{
-public:
- AudioStateInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (BluetoothA2dpAudioState& aArg1,
- BluetoothAddress& aArg2) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read state */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read address */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonA2dpModule::AudioStateNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
AudioStateNotification::Dispatch(
&BluetoothA2dpNotificationHandler::AudioStateNotification,
- AudioStateInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
-// Init operator class for AudioConfigNotification
-class BluetoothDaemonA2dpModule::AudioConfigInitOp final
- : private PDUInitOp
-{
-public:
- AudioConfigInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (BluetoothAddress& aArg1, uint32_t aArg2, uint8_t aArg3) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read address */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read sample rate */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read channel count */
- rv = UnpackPDU(pdu, aArg3);
- if (NS_FAILED(rv)) {
- return rv;
- }
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonA2dpModule::AudioConfigNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
AudioConfigNotification::Dispatch(
&BluetoothA2dpNotificationHandler::AudioConfigNotification,
- AudioConfigInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
void
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.h
index e1e1d648f739..2ddf1deaea1d 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.h
@@ -110,10 +110,6 @@ protected:
const BluetoothAddress&, uint32_t, uint8_t>
AudioConfigNotification;
- class ConnectionStateInitOp;
- class AudioStateInitOp;
- class AudioConfigInitOp;
-
void ConnectionStateNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.cpp
index 1a12e82d08ed..709fa44585d9 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.cpp
@@ -738,40 +738,13 @@ BluetoothDaemonAvrcpModule::VolumeChangeNtf(
UnpackPDUInitOp(aPDU));
}
-// Init operator class for PassthroughCmdNotification
-class BluetoothDaemonAvrcpModule::PassthroughCmdInitOp final
- : private PDUInitOp
-{
-public:
- PassthroughCmdInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (int& aArg1, int& aArg2) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- nsresult rv = UnpackPDU(pdu, UnpackConversion(aArg1));
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = UnpackPDU(pdu, UnpackConversion(aArg2));
- if (NS_FAILED(rv)) {
- return rv;
- }
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonAvrcpModule::PassthroughCmdNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
PassthroughCmdNotification::Dispatch(
&BluetoothAvrcpNotificationHandler::PassthroughCmdNotification,
- PassthroughCmdInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
#endif
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.h
index 6327a75089f7..f06ebc0cc845 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.h
@@ -243,14 +243,13 @@ protected:
VolumeChangeNotification;
typedef mozilla::ipc::DaemonNotificationRunnable2<
- NotificationHandlerWrapper, void, int, int>
+ NotificationHandlerWrapper, void, uint8_t, uint8_t, int, int>
PassthroughCmdNotification;
class GetElementAttrInitOp;
class GetPlayerAppAttrsTextInitOp;
class GetPlayerAppValueInitOp;
class GetPlayerAppValuesTextInitOp;
- class PassthroughCmdInitOp;
class RemoteFeatureInitOp;
void RemoteFeatureNtf(const DaemonSocketPDUHeader& aHeader,
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.cpp
index 986ef448ed6c..a0402802e173 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.cpp
@@ -945,201 +945,40 @@ BluetoothDaemonCoreModule::DiscoveryStateChangedNtf(
UnpackPDUInitOp(aPDU));
}
-// Init operator class for PinRequestNotification
-class BluetoothDaemonCoreModule::PinRequestInitOp final
- : private PDUInitOp
-{
-public:
- PinRequestInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (BluetoothAddress& aArg1, BluetoothRemoteName& aArg2,
- uint32_t& aArg3) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read remote address */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read remote name */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read CoD */
- rv = UnpackPDU(pdu, aArg3);
- if (NS_FAILED(rv)) {
- return rv;
- }
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonCoreModule::PinRequestNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
PinRequestNotification::Dispatch(
&BluetoothNotificationHandler::PinRequestNotification,
- PinRequestInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
-// Init operator class for SspRequestNotification
-class BluetoothDaemonCoreModule::SspRequestInitOp final
- : private PDUInitOp
-{
-public:
- SspRequestInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (BluetoothAddress& aArg1, BluetoothRemoteName& aArg2,
- uint32_t& aArg3, BluetoothSspVariant& aArg4,
- uint32_t& aArg5) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read remote address */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read remote name */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read CoD */
- rv = UnpackPDU(pdu, aArg3);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read pairing variant */
- rv = UnpackPDU(pdu, aArg4);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read passkey */
- rv = UnpackPDU(pdu, aArg5);
- if (NS_FAILED(rv)) {
- return rv;
- }
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonCoreModule::SspRequestNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
SspRequestNotification::Dispatch(
&BluetoothNotificationHandler::SspRequestNotification,
- SspRequestInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
-// Init operator class for BondStateChangedNotification
-class BluetoothDaemonCoreModule::BondStateChangedInitOp final
- : private PDUInitOp
-{
-public:
- BondStateChangedInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (BluetoothStatus& aArg1, BluetoothAddress& aArg2,
- BluetoothBondState& aArg3) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read status */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read remote address */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read bond state */
- rv = UnpackPDU(pdu, aArg3);
- if (NS_FAILED(rv)) {
- return rv;
- }
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonCoreModule::BondStateChangedNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
BondStateChangedNotification::Dispatch(
&BluetoothNotificationHandler::BondStateChangedNotification,
- BondStateChangedInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
-// Init operator class for AclStateChangedNotification
-class BluetoothDaemonCoreModule::AclStateChangedInitOp final
- : private PDUInitOp
-{
-public:
- AclStateChangedInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (BluetoothStatus& aArg1, BluetoothAddress& aArg2,
- BluetoothAclState& aArg3) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read status */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read remote address */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read ACL state */
- rv = UnpackPDU(pdu, aArg3);
- if (NS_FAILED(rv)) {
- return rv;
- }
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonCoreModule::AclStateChangedNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
AclStateChangedNotification::Dispatch(
&BluetoothNotificationHandler::AclStateChangedNotification,
- AclStateChangedInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
// Init operator class for DutModeRecvNotification
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.h
index aa24f889628e..f40506ca469f 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.h
@@ -298,14 +298,10 @@ private:
NotificationHandlerWrapper, void, BluetoothStatus, uint16_t>
LeTestModeNotification;
- class AclStateChangedInitOp;
class AdapterPropertiesInitOp;
- class BondStateChangedInitOp;
class DeviceFoundInitOp;
class DutModeRecvInitOp;
- class PinRequestInitOp;
class RemoteDevicePropertiesInitOp;
- class SspRequestInitOp;
void AdapterStateChangedNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
index 4cb694ade199..bccd546550cd 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
@@ -1568,56 +1568,13 @@ BluetoothDaemonGattModule::ClientScanResultNtf(
ClientScanResultInitOp(aPDU));
}
-// Init operator class for ClientConnect/DisconnectNotification
-class BluetoothDaemonGattModule::ClientConnectDisconnectInitOp final
- : private PDUInitOp
-{
-public:
- ClientConnectDisconnectInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (int& aArg1,
- BluetoothGattStatus& aArg2,
- int& aArg3,
- BluetoothAddress& aArg4) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read connection ID */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read status */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read client interface */
- rv = UnpackPDU(pdu, aArg3);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read address */
- rv = UnpackPDU(pdu, aArg4);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonGattModule::ClientConnectNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
ClientConnectNotification::Dispatch(
&BluetoothGattNotificationHandler::ConnectNotification,
- ClientConnectDisconnectInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
void
@@ -1626,7 +1583,7 @@ BluetoothDaemonGattModule::ClientDisconnectNtf(
{
ClientDisconnectNotification::Dispatch(
&BluetoothGattNotificationHandler::DisconnectNotification,
- ClientConnectDisconnectInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
void
@@ -1737,56 +1694,13 @@ BluetoothDaemonGattModule::ClientExecuteWriteNtf(
UnpackPDUInitOp(aPDU));
}
-// Init operator class for ClientReadRemoteRssiNotification
-class BluetoothDaemonGattModule::ClientReadRemoteRssiInitOp final
- : private PDUInitOp
-{
-public:
- ClientReadRemoteRssiInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (int& aArg1,
- BluetoothAddress& aArg2,
- int& aArg3,
- BluetoothGattStatus& aArg4) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read client interface */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read address */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read RSSI */
- rv = UnpackPDU(pdu, aArg3);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read status */
- rv = UnpackPDU(pdu, aArg4);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonGattModule::ClientReadRemoteRssiNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
ClientReadRemoteRssiNotification::Dispatch(
&BluetoothGattNotificationHandler::ReadRemoteRssiNotification,
- ClientReadRemoteRssiInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
void
@@ -1922,68 +1836,13 @@ BluetoothDaemonGattModule::ServerServiceDeletedNtf(
UnpackPDUInitOp(aPDU));
}
-// Init operator class for ServerRequestReadNotification
-class BluetoothDaemonGattModule::ServerRequestReadInitOp final
- : private PDUInitOp
-{
-public:
- ServerRequestReadInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (int& aArg1,
- int& aArg2,
- BluetoothAddress& aArg3,
- BluetoothAttributeHandle& aArg4,
- int& aArg5,
- bool& aArg6) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read connection ID */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read trans ID */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read address */
- rv = UnpackPDU(pdu, aArg3);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read attribute handle */
- rv = UnpackPDU(pdu, aArg4);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read offset */
- rv = UnpackPDU(pdu, aArg5);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read isLong */
- rv = UnpackPDU(pdu, aArg6);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonGattModule::ServerRequestReadNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
ServerRequestReadNotification::Dispatch(
&BluetoothGattNotificationHandler::RequestReadNotification,
- ServerRequestReadInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
// Init operator class for ServerRequestWriteNotification
@@ -2069,56 +1928,13 @@ BluetoothDaemonGattModule::ServerRequestWriteNtf(
ServerRequestWriteInitOp(aPDU));
}
-// Init operator class for ServerRequestExecuteWriteNotification
-class BluetoothDaemonGattModule::ServerRequestExecuteWriteInitOp final
- : private PDUInitOp
-{
-public:
- ServerRequestExecuteWriteInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (int& aArg1,
- int& aArg2,
- BluetoothAddress& aArg3,
- bool& aArg4) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read connection ID */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read trans ID */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read address */
- rv = UnpackPDU(pdu, aArg3);
- if (NS_FAILED(rv)) {
- return rv;
- }
- /* Read execute write */
- rv = UnpackPDU(pdu, aArg4);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonGattModule::ServerRequestExecuteWriteNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
ServerRequestExecuteWriteNotification::Dispatch(
&BluetoothGattNotificationHandler::RequestExecuteWriteNotification,
- ServerRequestExecuteWriteInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
void
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h
index 7e106c2bb77d..fc7183fd8af6 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h
@@ -681,14 +681,10 @@ protected:
BluetoothGattStatus, int>
ServerResponseConfirmationNotification;
- class ClientScanResultInitOp;
- class ClientConnectDisconnectInitOp;
- class ClientReadRemoteRssiInitOp;
class ClientGetDeviceTypeInitOp;
+ class ClientScanResultInitOp;
class ServerConnectionInitOp;
- class ServerRequestReadInitOp;
class ServerRequestWriteInitOp;
- class ServerRequestExecuteWriteInitOp;
void ClientRegisterNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.cpp
index 05e3ccf54b1c..1fafbce9582b 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.cpp
@@ -777,44 +777,13 @@ BluetoothDaemonHandsfreeModule::ConnectionStateNtf(
ConnectionStateInitOp(aPDU));
}
-// Init operator class for AudioStateNotification
-class BluetoothDaemonHandsfreeModule::AudioStateInitOp final
- : private PDUInitOp
-{
-public:
- AudioStateInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (BluetoothHandsfreeAudioState& aArg1,
- BluetoothAddress& aArg2) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read state */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read address */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonHandsfreeModule::AudioStateNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
AudioStateNotification::Dispatch(
&BluetoothHandsfreeNotificationHandler::AudioStateNotification,
- AudioStateInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
// Init operator class for VoiceRecognitionNotification
@@ -1381,44 +1350,13 @@ BluetoothDaemonHandsfreeModule::KeyPressedNtf(
KeyPressedInitOp(aPDU));
}
-// Init operator class for WbsNotification
-class BluetoothDaemonHandsfreeModule::WbsInitOp final
- : private PDUInitOp
-{
-public:
- WbsInitOp(DaemonSocketPDU& aPDU)
- : PDUInitOp(aPDU)
- { }
-
- nsresult
- operator () (BluetoothHandsfreeWbsConfig& aArg1, BluetoothAddress& aArg2) const
- {
- DaemonSocketPDU& pdu = GetPDU();
-
- /* Read state */
- nsresult rv = UnpackPDU(pdu, aArg1);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- /* Read address */
- rv = UnpackPDU(pdu, aArg2);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- WarnAboutTrailingData();
- return NS_OK;
- }
-};
-
void
BluetoothDaemonHandsfreeModule::WbsNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
WbsNotification::Dispatch(
&BluetoothHandsfreeNotificationHandler::WbsNotification,
- WbsInitOp(aPDU));
+ UnpackPDUInitOp(aPDU));
}
void
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.h
index 83f9d32e2fc9..fe8345611fef 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.h
@@ -314,7 +314,6 @@ protected:
WbsNotification;
class ConnectionStateInitOp;
- class AudioStateInitOp;
class VoiceRecognitionInitOp;
class AnswerCallInitOp;
class HangupCallInitOp;
@@ -330,7 +329,6 @@ protected:
class VolumeInitOp;
class UnknownAtInitOp;
class KeyPressedInitOp;
- class WbsInitOp;
void ConnectionStateNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
diff --git a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
index 2e7ae85616bb..ad42626a29a8 100644
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -1890,9 +1890,11 @@ BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState)
if (!mEnabled) {
static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = {
- BluetoothHfpManager::DeinitHfpInterface,
+ // Cleanup interfaces in opposite order to initialization.
+ BluetoothGattManager::DeinitGattInterface,
+ BluetoothAvrcpManager::DeinitAvrcpInterface,
BluetoothA2dpManager::DeinitA2dpInterface,
- BluetoothGattManager::DeinitGattInterface
+ BluetoothHfpManager::DeinitHfpInterface
};
// Return error if BluetoothService is unavailable
diff --git a/dom/browser-element/BrowserElementChildPreload.js b/dom/browser-element/BrowserElementChildPreload.js
index d4adc585a854..9eb20d888bfa 100644
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -916,6 +916,8 @@ BrowserElementChild.prototype = {
// Pass along the position where the context menu should be located
menuData.clientX = e.clientX;
menuData.clientY = e.clientY;
+ menuData.screenX = e.screenX;
+ menuData.screenY = e.screenY;
// The value returned by the contextmenu sync call is true if the embedder
// called preventDefault() on its contextmenu event.
diff --git a/dom/telephony/gonk/TelephonyService.js b/dom/telephony/gonk/TelephonyService.js
index d9f78b517f6b..06c24f7174fa 100644
--- a/dom/telephony/gonk/TelephonyService.js
+++ b/dom/telephony/gonk/TelephonyService.js
@@ -2211,10 +2211,9 @@ TelephonyService.prototype = {
aFailCause = RIL.GECKO_CALL_ERROR_NORMAL_CALL_CLEARING) {
if (DEBUG) debug("_disconnectCalls: " + JSON.stringify(aCalls));
- // Child cannot live without parent. Let's find all the calls that need to
- // be disconnected.
+ // In addition to the disconnected call itself, its decedent calls should be
+ // treated as disconnected calls as well.
let disconnectedCalls = aCalls.slice();
-
for (let call in aCalls) {
while (call.childId) {
call = this._currentCalls[aClientId][call.childId];
@@ -2231,8 +2230,8 @@ TelephonyService.prototype = {
call.state = nsITelephonyService.CALL_STATE_DISCONNECTED;
call.disconnectedReason = aFailCause;
- if (call.parentId) {
- let parentCall = this._currentCalls[aClientId][call.parentId];
+ let parentCall = this._currentCalls[aClientId][call.parentId];
+ if (parentCall) {
delete parentCall.childId;
}
diff --git a/dom/telephony/test/marionette/head.js b/dom/telephony/test/marionette/head.js
index a092585cce58..b95ddf8c7e15 100644
--- a/dom/telephony/test/marionette/head.js
+++ b/dom/telephony/test/marionette/head.js
@@ -99,6 +99,121 @@ var emulator = (function() {
};
}());
+/**
+ * Modem Helper
+ *
+ * TODO: Should select which modem here to support multi-SIM
+ */
+
+function modemHelperGenerator() {
+ function Modem(aClientID) {
+ this.clientID = aClientID;
+ }
+ Modem.prototype = {
+ clientID: 0,
+
+ voiceTypeToTech: function(aVoiceType) {
+ switch(aVoiceType) {
+ case "gsm":
+ case "gprs":
+ case "edge":
+ return "gsm";
+
+ case "umts":
+ case "hsdpa":
+ case "hsupa":
+ case "hspa":
+ case "hspa+":
+ return "wcdma";
+
+ case "is95a":
+ case "is95b":
+ case "1xrtt":
+ return "cdma";
+
+ case "evdo0":
+ case "evdoa":
+ case "evdob":
+ return "evdo";
+
+ case "ehrpd":
+ return "ehrpd";
+
+ case "lte":
+ return "lte";
+
+ default:
+ return null;
+ }
+ },
+
+ isCDMA: function() {
+ var mobileConn = navigator.mozMobileConnections[this.clientID];
+ var tech = mobileConn && this.voiceTypeToTech(mobileConn.voice.type);
+ return tech === "cdma" || tech === "evdo" || tech == "ehrpd";
+ },
+
+ isGSM: function() {
+ var mobileConn = navigator.mozMobileConnections[this.clientID];
+ var tech = mobileConn && this.voiceTypeToTech(mobileConn.voice.type);
+ return tech === "gsm" || tech === "wcdma" || tech === "lte";
+ },
+
+ /**
+ * @return Promise:
+ */
+ changeTech: function(aTech, aMask) {
+ let target = navigator.mozMobileConnections[this.clientID];
+
+ let mask = aMask || {
+ gsm: "gsm",
+ wcdma: "gsm/wcdma",
+ cdma: "cdma",
+ evdo: "evdo0",
+ ehrpd: "ehrpd",
+ lte: "lte"
+ }[aTech];
+
+ let waitForExpectedTech = () => {
+ return new Promise((aResolve, aReject) => {
+ let listener = aEvent => {
+ log("MobileConnection[" + this.clientID + "] " +
+ "received event 'voicechange'");
+ if (aTech === this.voiceTypeToTech(target.voice.type)) {
+ target.removeEventListener("voicechange", listener);
+ aResolve();
+ }
+ };
+
+ target.addEventListener("voicechange", listener);
+ });
+ };
+
+ // TODO: Should select a modem here to support multi-SIM
+ let changeToExpectedTech = () => {
+ return Promise.resolve()
+ .then(() => emulator.runCmd("modem tech " + aTech + " " + mask))
+ .then(() => emulator.runCmd("modem tech"))
+ .then(result => is(result[0], aTech + " " + mask,
+ "Check modem 'tech/preferred mask'"));
+ }
+
+ return aTech === this.voiceTypeToTech(target.voice.type)
+ ? Promise.resolve()
+ : Promise.all([waitForExpectedTech(), changeToExpectedTech()]);
+ }
+ };
+
+ let modems = [];
+ for (let i = 0; i < navigator.mozMobileConnections.length; ++i) {
+ modems.push(new Modem(i));
+ }
+ return modems;
+}
+
+let Modems = modemHelperGenerator();
+let Modem = Modems[0];
+
/**
* Telephony related helper functions.
*/
@@ -276,70 +391,6 @@ var emulator = (function() {
});
}
- /**
- * @param aVoiceType
- * The voice type of a mobileConnection, which can be obtained from
- * |.voice.type|.
- * @return A string with format of the emulator voice tech.
- */
- function voiceTypeToTech(aVoiceType) {
- switch(aVoiceType) {
- case "gsm":
- case "gprs":
- case "edge":
- return "gsm";
-
- case "umts":
- case "hsdpa":
- case "hsupa":
- case "hspa":
- case "hspa+":
- return "wcdma";
-
- case "is95a":
- case "is95b":
- case "1xrtt":
- return "cdma";
-
- case "evdo0":
- case "evdoa":
- case "evdob":
- return "evdo";
-
- case "ehrpd":
- case "lte":
- return "lte";
-
- default:
- return null;
- }
- }
-
- /**
- * @return Promise
- */
- function changeModemTech(aTech, aPreferredMask) {
- let mobileConn = navigator.mozMobileConnections[0];
-
- function isTechMatched() {
- return aTech === voiceTypeToTech(mobileConn.voice.type);
- }
-
- let promise1 = isTechMatched() ? Promise.resolve()
- : waitForEvent(mobileConn,
- "voicechange",
- isTechMatched);
-
- let promise2 = Promise.resolve()
- .then(() => emulator.runCmd("modem tech " + aTech + " " + aPreferredMask))
- .then(() => emulator.runCmd("modem tech"))
- .then(result => is(result[0],
- aTech + " " + aPreferredMask,
- "Check modem 'tech/preferred mask'"));
-
- return Promise.all([promise1, promise2]);
- }
-
/**
* @return Promise
*/
@@ -361,7 +412,7 @@ var emulator = (function() {
return Promise.all(hangUpPromises)
.then(() => {
- return emulator.runCmd("gsm clear").then(waitForNoCall);
+ return emulator.runCmd("telephony clear").then(waitForNoCall);
})
.then(waitForNoCall);
}
@@ -423,6 +474,11 @@ var emulator = (function() {
checkState(null, [], "", []);
}
+
+ /****************************************************************************
+ **** Check Functions ****
+ ****************************************************************************/
+
/**
* Convenient helper to compare two call lists (order is not important).
*/
@@ -478,7 +534,7 @@ var emulator = (function() {
* @return Promise
*/
function checkEmulatorCallList(expectedCallList) {
- return emulator.runCmd("gsm list").then(result => {
+ return emulator.runCmd("telephony list").then(result => {
log("Call list is now: " + result);
for (let i = 0; i < expectedCallList.length; ++i) {
is(result[i], expectedCallList[i], "emulator calllist");
@@ -532,8 +588,168 @@ var emulator = (function() {
}
/**
- * Request utility functions.
+ * The factory function for creating an expected call.
+ *
+ * @param aReference
+ * The reference of the telephonyCall object.
+ * @param aNumber
+ * The call number.
+ * @param aConference
+ * Shows whether the call belongs to the conference.
+ * @param aDirection
+ * The direction of the call, "in" for inbound, and "out" for outbound.
+ * @param aState
+ * The expected state of the call.
+ * @param aEmulatorState
+ * The state logged in emulator now, may be different from aState.
+ * @param aDisconnectedReason
+ * The disconnected reason if the call becomed disconnected.
*/
+ function createExptectedCall(aReference, aNumber, aConference, aDirection,
+ aState, aEmulatorState, aDisconnectedReason) {
+ return {
+ reference: aReference,
+ number: aNumber,
+ conference: aConference,
+ direction: aDirection,
+ state: aState,
+ emulatorState: aEmulatorState,
+ disconnectedReason: aDisconnectedReason
+ };
+ }
+
+ /**
+ * Check telephony.active
+ *
+ * @param aExpectedCalls
+ * An array of expected calls.
+ * @param aExpectedCallsInConference
+ * An array of expected calls in the conference.
+ */
+ function checkActive(aExpectedCalls, aExpectedCallsInConference) {
+ // Get the active call
+ let calls = aExpectedCalls && aExpectedCalls.filter(aExpectedCall => {
+ return aExpectedCall.state === "connected" ||
+ aExpectedCall.state === "alerting" ||
+ aExpectedCall.state === "dialing";
+ });
+
+ ok(calls.length < 2, "Too many actives call in telephony.calls");
+ let activeCall = calls.length ? calls[0].reference : null;
+
+ // Get the active conference
+ let callsInConference = aExpectedCallsInConference || [];
+ let activeConference = callsInConference.length &&
+ callsInConference[0].state === "connected"
+ ? navigator.mozTelephony.conferenceGroup
+ : null;
+
+ // Check telephony.active
+ ok(!(activeCall && activeConference),
+ "An active call cannot coexist with an active conference call.");
+ is(telephony.active, activeCall || activeConference, "check Active");
+ }
+
+ /**
+ * Check whether the data in telephony and emulator meets our expectation.
+ *
+ * NOTE: Conference call is not supported in this function yet, so related
+ * checks are skipped.
+ *
+ * Fulfill params:
+ * {
+ * reference, -- the reference of the call object instance.
+ * number, -- the call number.
+ * conference, -- shows whether it belongs to the conference.
+ * direction, -- "in" for inbound, and "out" for outbound.
+ * state, -- the call state.
+ * emulatorState, -- the call state logged in emulator now.
+ * disconnectedReason, -- the disconnected reason of a disconnected call.
+ * }
+ *
+ * @param aExpectedCalls
+ * An array of call records.
+ * @return Promise
+ */
+ function equals(aExpectedCalls) {
+ // Classify calls
+ let callsInTelephony = [];
+ let CallsInConference = [];
+
+ aExpectedCalls.forEach(function(aCall) {
+ if (aCall.state === "disconnected") {
+ is(aCall.disconnectedReason,
+ aCall.reference.disconnectedReason,
+ "Check disconnectedReason");
+ return;
+ }
+
+ if (aCall.conference) {
+ CallsInConference.push(aCall);
+ return;
+ }
+
+ callsInTelephony.push(aCall);
+ ok(!aCall.secondId, "For a telephony call, the secondId must be null");
+ });
+
+ // Check the active connection
+ checkActive(callsInTelephony, CallsInConference);
+
+ // Check telephony.calls
+ is(telephony.calls.length,
+ callsInTelephony.length,
+ "Check telephony.calls.length");
+
+ callsInTelephony.forEach(aExpectedCall => {
+ let number = aExpectedCall.number;
+ let call = telephony.calls.find(aCall => aCall.id.number === number);
+ if (!call) {
+ ok(false, "telephony.calls lost the call(number: " + number + ")");
+ return;
+ }
+
+ is(call, aExpectedCall.reference,
+ "Check the object reference of number:" + number);
+
+ is(call.state, aExpectedCall.state,
+ "Check call.state of number:" + number);
+ });
+
+ // Check conference.calls
+ // NOTE: This function doesn't support conference call now, so the length of
+ // |CallsInConference| should be 0, and the conference state shoul be "".
+ is(conference.state, "", "Conference call is not supported yet.");
+ is(CallsInConference.length, 0, "Conference call is not supported yet.");
+
+ // Check the emulator call list
+ // NOTE: Conference is not supported yet, so |CallsInConference| is ignored.
+ let strings = callsInTelephony.map(aCall => {
+ // The emulator doesn't have records for disconnected calls.
+ if (aCall.emulatorState === "disconnected") {
+ return null;
+ }
+
+ let state = {
+ alerting: "ringing",
+ connected: "active",
+ held: "held",
+ incoming: "incoming"
+ }[aCall.state];
+
+ state = aCall.emulatorState || state;
+ let prefix = (aCall.direction === "in") ? "inbound from "
+ : "outbound to ";
+
+ return state ? (prefix + aCall.number + " : " + state) : null;
+ });
+
+ return checkEmulatorCallList(strings.filter(aString => aString));
+ }
+
+ /****************************************************************************
+ **** Request utility functions ****
+ ****************************************************************************/
/**
* Make an outgoing call.
@@ -558,7 +774,13 @@ var emulator = (function() {
is(outCall.state, "dialing");
is(outCall.serviceId, serviceId);
})
- .then(() => waitForNamedStateEvent(outCall, "alerting"));
+ .then(() => {
+ // A CDMA call goes to connected state directly when the operator find
+ // its callee, which makes the "connected" state in CDMA calls behaves
+ // like the "alerting" state in GSM calls.
+ let state = Modems[serviceId].isGSM() ? "alerting" : "connected";
+ return waitForNamedStateEvent(outCall, state);
+ });
}
/**
@@ -581,7 +803,13 @@ var emulator = (function() {
is(outCall.id.number, number);
is(outCall.state, "dialing");
})
- .then(() => waitForNamedStateEvent(outCall, "alerting"))
+ .then(() => {
+ // Similar to function |dial|, a CDMA call directly goes to connected
+ // state when the operator find its callee.
+ let state = Modems[outCall.serviceId].isGSM() ? "alerting"
+ : "connected";
+ return waitForNamedStateEvent(outCall, state);
+ })
.then(() => {
is(outCall.emergency, true, "check emergency");
return outCall;
@@ -651,19 +879,23 @@ var emulator = (function() {
/**
* Hold a call.
*
- * @param call
+ * @param aCall
* A TelephonyCall object.
+ * @param aWaitForEvent
+ * Decide whether to wait for the state event.
* @return Promise
*/
- function hold(call) {
+ function hold(aCall, aWaitForEvent = true) {
log("Putting the call on hold.");
let promises = [];
- promises.push(waitForNamedStateEvent(call, "held"));
- promises.push(call.hold());
+ if (aWaitForEvent) {
+ promises.push(waitForNamedStateEvent(aCall, "held"));
+ }
+ promises.push(aCall.hold());
- return Promise.all(promises).then(() => call);
+ return Promise.all(promises).then(() => aCall);
}
/**
@@ -673,7 +905,7 @@ var emulator = (function() {
* A TelephonyCall object.
* @return Promise
*/
- function resume(call) {
+ function resume(call, aWaitForEvent = true) {
log("Resuming the held call.");
let promises = [];
@@ -721,8 +953,10 @@ var emulator = (function() {
numberPresentation = numberPresentation || "";
name = name || "";
namePresentation = namePresentation || "";
- emulator.runCmd("gsm call " + number + "," + numberPresentation + "," + name +
- "," + namePresentation);
+ emulator.runCmd("telephony call " + number +
+ "," + numberPresentation +
+ "," + name +
+ "," + namePresentation);
return waitForEvent(telephony, "incoming")
.then(event => {
@@ -747,9 +981,14 @@ var emulator = (function() {
function remoteAnswer(call) {
log("Remote answering the call: " + call.id.number);
- emulator.runCmd("gsm accept " + call.id.number);
+ emulator.runCmd("telephony accept " + call.id.number);
- return waitForNamedStateEvent(call, "connected");
+ // A CDMA call goes to connected state directly when the operator find its
+ // callee, which makes the "connected" state in CDMA calls behaves like the
+ // "alerting" state in GSM calls, so we don't have to wait for the call to
+ // change to "connected" state here for CDMA calls.
+ return Modem.isCDMA() ? Promise.resolve()
+ : waitForNamedStateEvent(call, "connected");
}
/**
@@ -762,7 +1001,7 @@ var emulator = (function() {
function remoteHangUp(call) {
log("Remote hanging up the call: " + call.id.number);
- emulator.runCmd("gsm cancel " + call.id.number);
+ emulator.runCmd("telephony cancel " + call.id.number);
return waitForNamedStateEvent(call, "disconnected");
}
@@ -1216,7 +1455,6 @@ var emulator = (function() {
this.gWaitForNamedStateEvent = waitForNamedStateEvent;
this.gWaitForStateChangeEvent = waitForStateChangeEvent;
this.gCheckInitialState = checkInitialState;
- this.gChangeModemTech = changeModemTech;
this.gClearCalls = clearCalls;
this.gOutCallStrPool = outCallStrPool;
this.gInCallStrPool = inCallStrPool;
@@ -1244,6 +1482,25 @@ var emulator = (function() {
this.gSetupConference = setupConference;
this.gSetRadioEnabled = setRadioEnabled;
this.gSetRadioEnabledAll = setRadioEnabledAll;
+
+ // Telephony helper
+ this.TelephonyHelper = {
+ dial: dial,
+ answer: answer,
+ hangUp: hangUp,
+ hold: hold,
+ resume: resume,
+ equals: equals,
+ createExptectedCall: createExptectedCall
+ };
+
+ // Remote Utils, TODO: This should be an array for multi-SIM scenarios
+ this.Remotes = [{
+ dial: remoteDial,
+ answer: remoteAnswer,
+ hangUp: remoteHangUp
+ }];
+ this.Remote = this.Remotes[0];
}());
function _startTest(permissions, test) {
diff --git a/dom/telephony/test/marionette/manifest.ini b/dom/telephony/test/marionette/manifest.ini
index 228778623bc1..7e83e675340d 100644
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -24,6 +24,8 @@ qemu = true
[test_dtmf.js]
[test_emergency.js]
[test_emergency_label.js]
+[test_gsm_cdma_incoming_basic_operations.js]
+[test_gsm_cdma_outgoing_basic_operations.js]
[test_incall_mmi_call_hold.js]
[test_incall_mmi_call_waiting.js]
[test_incall_mmi_conference.js]
@@ -31,7 +33,6 @@ qemu = true
[test_incoming_already_connected.js]
[test_incoming_already_held.js]
[test_incoming_answer_hangup_oncallschanged.js]
-[test_incoming_basic_operations.js]
[test_incoming_onstatechange.js]
[test_mmi_call_barring.js]
[test_mmi_call_forwarding.js]
@@ -52,7 +53,6 @@ qemu = true
[test_outgoing_answer_radio_off.js]
[test_outgoing_auto_hold.js]
[test_outgoing_badNumber.js]
-[test_outgoing_basic_operations.js]
[test_outgoing_busy.js]
[test_outgoing_from_stk.js]
[test_outgoing_onstatechange.js]
@@ -64,3 +64,4 @@ qemu = true
[test_system_message_telephony_call_ended.js]
[test_TelephonyUtils.js]
[test_temporary_clir.js]
+
diff --git a/dom/telephony/test/marionette/test_TelephonyUtils.js b/dom/telephony/test/marionette/test_TelephonyUtils.js
index 7cecd11b0b00..a0b5c3a0556d 100644
--- a/dom/telephony/test/marionette/test_TelephonyUtils.js
+++ b/dom/telephony/test/marionette/test_TelephonyUtils.js
@@ -78,7 +78,7 @@ function test_oneCall() {
let p = waitForStateChanged(aAllInfo => {
return aAllInfo[0].callState === Ci.nsITelephonyService.CALL_STATE_CONNECTED;
});
- emulator.runCmd("gsm accept " + number);
+ emulator.runCmd("telephony accept " + number);
return p;
})
.then(() => {
@@ -87,7 +87,7 @@ function test_oneCall() {
})
.then(() => {
let p = TelephonyUtils.waitForNoCalls();
- emulator.runCmd("gsm cancel " + number);
+ emulator.runCmd("telephony cancel " + number);
return p;
});
}
diff --git a/dom/telephony/test/marionette/test_consecutive_hold.js b/dom/telephony/test/marionette/test_consecutive_hold.js
index c13f95a9b1ba..c09c179fd1b8 100644
--- a/dom/telephony/test/marionette/test_consecutive_hold.js
+++ b/dom/telephony/test/marionette/test_consecutive_hold.js
@@ -24,7 +24,7 @@ startTest(function() {
// Disable the Hold function of the emulator, then hold the active call,
// where the hold request will fail and the call will remain active.
- .then(() => emulator.runCmd("gsm disable hold"))
+ .then(() => emulator.runCmd("telephony disable hold"))
.then(() => gHold(inCall))
.then(() => ok(false, "This hold request should be rejected."),
() => log("This hold request is rejected as expected."))
@@ -33,7 +33,7 @@ startTest(function() {
// Enable the Hold function of the emulator, then hold the active call,
// where the hold request should succeed and the call should become held.
- .then(() => emulator.runCmd("gsm enable hold"))
+ .then(() => emulator.runCmd("telephony enable hold"))
.then(() => gHold(inCall))
.then(() => log("This hold request is resolved as expected."),
() => ok(false, "This hold request should be resolved."))
@@ -47,6 +47,6 @@ startTest(function() {
// Clean Up
.catch(error => ok(false, "Promise reject: " + error))
- .then(() => emulator.runCmd("gsm enable hold"))
+ .then(() => emulator.runCmd("telephony enable hold"))
.then(finish);
});
diff --git a/dom/telephony/test/marionette/test_gsm_cdma_incoming_basic_operations.js b/dom/telephony/test/marionette/test_gsm_cdma_incoming_basic_operations.js
new file mode 100644
index 000000000000..cf4fe6f60c9f
--- /dev/null
+++ b/dom/telephony/test/marionette/test_gsm_cdma_incoming_basic_operations.js
@@ -0,0 +1,170 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 90000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+/******************************************************************************
+ **** Basic Operations ****
+ ******************************************************************************/
+
+const IncomingNumber = "1111110000";
+
+function exptectedCall(aCall, aState, aEmulatorState = null) {
+ let disconnectedReason = aState === "disconnected" ? "NormalCallClearing"
+ : null;
+
+ return TelephonyHelper.createExptectedCall(aCall, IncomingNumber, false,
+ "in", aState, aEmulatorState,
+ disconnectedReason);
+}
+
+function incoming(aNumber) {
+ let ret;
+ return Remote.dial(aNumber)
+ .then(call => ret = call)
+ .then(() => TelephonyHelper.equals([exptectedCall(ret, "incoming")]))
+ .then(() => ret);
+}
+
+function answer(aCall) {
+ let call = exptectedCall(aCall, "connected");
+ return TelephonyHelper.answer(aCall)
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+function hold(aCall) {
+ // Since a CDMA call doesn't have any notification for its state changing to
+ // "held" state, a telephonyCall is still remains in "connected" state when
+ // the call actually goes to "held" state, and we shouldn't wait for the state
+ // change event here.
+ let state = Modem.isGSM() ? "held" : "connected";
+ let call = exptectedCall(aCall, state,"held");
+ return TelephonyHelper.hold(aCall, Modem.isGSM())
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+function resume(aCall) {
+ // Similar to the hold case, there is no notification for a CDMA call's state
+ // change. Besides, a CDMA call still remains in "connected" state here, so we
+ // have to use |hold()| function here to resume the call. Otherwise, if we use
+ // |resume()| function, we'll get an invalid state error.
+ let call = exptectedCall(aCall, "connected");
+ return Modem.isGSM() ? TelephonyHelper.resume(aCall)
+ : TelephonyHelper.hold(aCall, false)
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+function hangUp(aCall) {
+ let call = exptectedCall(aCall, "disconnected");
+ return TelephonyHelper.hangUp(aCall)
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+function remoteHangUp(aCall) {
+ let call = exptectedCall(aCall, "disconnected");
+ return Remote.hangUp(aCall)
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+/******************************************************************************
+ **** Testcases ****
+ ******************************************************************************/
+
+function testIncomingReject() {
+ log("= testIncomingReject =");
+ return incoming(IncomingNumber)
+ .then(call => hangUp(call));
+}
+
+function testIncomingCancel() {
+ log("= testIncomingCancel =");
+ return incoming(IncomingNumber)
+ .then(call => remoteHangUp(call));
+}
+
+function testIncomingAnswerHangUp() {
+ log("= testIncomingAnswerHangUp =");
+ return incoming(IncomingNumber)
+ .then(call => answer(call))
+ .then(call => hangUp(call));
+}
+
+function testIncomingAnswerRemoteHangUp() {
+ log("= testIncomingAnswerRemoteHangUp =");
+ return incoming(IncomingNumber)
+ .then(call => answer(call))
+ .then(call => remoteHangUp(call));
+}
+
+function testIncomingAnswerHoldHangUp() {
+ log("= testIncomingAnswerHoldHangUp =");
+ return incoming(IncomingNumber)
+ .then(call => answer(call))
+ .then(call => hold(call))
+ .then(call => hangUp(call));
+}
+
+function testIncomingAnswerHoldRemoteHangUp() {
+ log("= testIncomingAnswerHoldRemoteHangUp =");
+ return incoming(IncomingNumber)
+ .then(call => answer(call))
+ .then(call => hold(call))
+ .then(call => remoteHangUp(call));
+}
+
+function testIncomingAnswerHoldResumeHangUp() {
+ log("= testIncomingAnswerHoldResumeHangUp =");
+ return incoming(IncomingNumber)
+ .then(call => answer(call))
+ .then(call => hold(call))
+ .then(call => resume(call))
+ .then(call => hangUp(call));
+}
+
+function testIncomingAnswerHoldResumeRemoteHangUp() {
+ log("= testIncomingAnswerHoldResumeRemoteHangUp =");
+ return incoming(IncomingNumber)
+ .then(call => answer(call))
+ .then(call => hold(call))
+ .then(call => resume(call))
+ .then(call => remoteHangUp(call));
+}
+
+/******************************************************************************
+ **** Test Launcher ****
+ ******************************************************************************/
+
+function runTestSuite(aTech, aTechMask) {
+ return Promise.resolve()
+ // Setup Environment
+ .then(() => Modem.changeTech(aTech, aTechMask))
+
+ // Tests
+ .then(() => testIncomingReject())
+ .then(() => testIncomingCancel())
+ .then(() => testIncomingAnswerHangUp())
+ .then(() => testIncomingAnswerRemoteHangUp())
+ .then(() => testIncomingAnswerHoldHangUp())
+ .then(() => testIncomingAnswerHoldRemoteHangUp())
+ .then(() => testIncomingAnswerHoldResumeHangUp())
+ .then(() => testIncomingAnswerHoldResumeRemoteHangUp())
+
+ // Restore Environment
+ .then(() => Modem.changeTech("wcdma"));
+}
+
+startTest(function() {
+ return Promise.resolve()
+ .then(() => runTestSuite("cdma"))
+ .then(() => runTestSuite("wcdma"))
+
+ .catch(error => ok(false, "Promise reject: " + error))
+ .then(finish);
+});
+
diff --git a/dom/telephony/test/marionette/test_gsm_cdma_outgoing_basic_operations.js b/dom/telephony/test/marionette/test_gsm_cdma_outgoing_basic_operations.js
new file mode 100644
index 000000000000..b53f4478c4f9
--- /dev/null
+++ b/dom/telephony/test/marionette/test_gsm_cdma_outgoing_basic_operations.js
@@ -0,0 +1,174 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 90000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+/******************************************************************************
+ **** Basic Operations ****
+ ******************************************************************************/
+
+const OutgoingNumber = "5555551111";
+
+function exptectedCall(aCall, aState, aEmulatorState = null) {
+ let disconnectedReason = aState === "disconnected" ? "NormalCallClearing"
+ : null;
+
+ return TelephonyHelper.createExptectedCall(aCall, OutgoingNumber, false,
+ "out", aState, aEmulatorState,
+ disconnectedReason);
+}
+
+function outgoing(aNumber) {
+ let ret;
+
+ // Since a CDMA call doesn't have "alerting" state, it directly goes to
+ // "connected" state instead.
+ let state = Modem.isCDMA() ? "connected" : "alerting";
+ return TelephonyHelper.dial(aNumber)
+ .then(call => ret = call)
+ .then(() => TelephonyHelper.equals([exptectedCall(ret, state)]))
+ .then(() => ret);
+}
+
+function remoteAnswer(aCall) {
+ let call = exptectedCall(aCall, "connected");
+ return Remote.answer(aCall)
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+function hold(aCall) {
+ // Since a CDMA call doesn't have any notification for its state changing to
+ // "held" state, a telephonyCall is still remains in "connected" state when
+ // the call actually goes to "held" state, and we shouldn't wait for the state
+ // change event here.
+ let state = Modem.isGSM() ? "held" : "connected";
+ let call = exptectedCall(aCall, state, "held");
+ return TelephonyHelper.hold(aCall, Modem.isGSM())
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+function resume(aCall) {
+ // Similar to the hold case, there is no notification for a CDMA call's state
+ // change. Besides, a CDMA call still remains in "connected" state here, so we
+ // have to use |hold()| function here to resume the call. Otherwise, if we use
+ // |resume()| function, we'll get an invalid state error.
+ let call = exptectedCall(aCall, "connected");
+ return Modem.isGSM() ? TelephonyHelper.resume(aCall)
+ : TelephonyHelper.hold(aCall, false)
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+function hangUp(aCall) {
+ let call = exptectedCall(aCall, "disconnected");
+ return TelephonyHelper.hangUp(aCall)
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+function remoteHangUp(aCall) {
+ let call = exptectedCall(aCall, "disconnected");
+ return Remote.hangUp(aCall)
+ .then(() => TelephonyHelper.equals([call]))
+ .then(() => aCall);
+}
+
+/******************************************************************************
+ **** Testcases ****
+ ******************************************************************************/
+
+function testOutgoingReject() {
+ log("= testOutgoingReject =");
+ return outgoing(OutgoingNumber)
+ .then(call => remoteHangUp(call));
+}
+
+function testOutgoingCancel() {
+ log("= testOutgoingCancel =");
+ return outgoing(OutgoingNumber)
+ .then(call => hangUp(call));
+}
+
+function testOutgoingAnswerHangUp() {
+ log("= testOutgoingAnswerHangUp =");
+ return outgoing(OutgoingNumber)
+ .then(call => remoteAnswer(call))
+ .then(call => hangUp(call));
+}
+
+function testOutgoingAnswerRemoteHangUp() {
+ log("= testOutgoingAnswerRemoteHangUp =");
+ return outgoing(OutgoingNumber)
+ .then(call => remoteAnswer(call))
+ .then(call => remoteHangUp(call));
+}
+
+function testOutgoingAnswerHoldHangUp() {
+ log("= testOutgoingAnswerHoldHangUp =");
+ return outgoing(OutgoingNumber)
+ .then(call => remoteAnswer(call))
+ .then(call => hold(call))
+ .then(call => hangUp(call));
+}
+
+function testOutgoingAnswerHoldRemoteHangUp() {
+ log("= testOutgoingAnswerHoldRemoteHangUp =");
+ return outgoing(OutgoingNumber)
+ .then(call => remoteAnswer(call))
+ .then(call => hold(call))
+ .then(call => remoteHangUp(call));
+}
+
+function testOutgoingAnswerHoldResumeHangUp() {
+ log("= testOutgoingAnswerHoldResumeHangUp =");
+ return outgoing(OutgoingNumber)
+ .then(call => remoteAnswer(call))
+ .then(call => hold(call))
+ .then(call => resume(call))
+ .then(call => hangUp(call));
+}
+
+function testOutgoingAnswerHoldResumeRemoteHangUp() {
+ log("= testOutgoingAnswerHoldResumeRemoteHangUp =");
+ return outgoing(OutgoingNumber)
+ .then(call => remoteAnswer(call))
+ .then(call => hold(call))
+ .then(call => resume(call))
+ .then(call => remoteHangUp(call));
+}
+
+/******************************************************************************/
+/*** Test Launcher ***/
+/******************************************************************************/
+
+function runTestSuite(aTech, aTechMask) {
+ return Promise.resolve()
+ // Setup Environment
+ .then(() => Modem.changeTech(aTech, aTechMask))
+
+ // Tests
+ .then(() => testOutgoingReject())
+ .then(() => testOutgoingCancel())
+ .then(() => testOutgoingAnswerHangUp())
+ .then(() => testOutgoingAnswerRemoteHangUp())
+ .then(() => testOutgoingAnswerHoldHangUp())
+ .then(() => testOutgoingAnswerHoldRemoteHangUp())
+ .then(() => testOutgoingAnswerHoldResumeHangUp())
+ .then(() => testOutgoingAnswerHoldResumeRemoteHangUp())
+
+ // Restore Environment
+ .then(() => Modem.changeTech("wcdma"));
+}
+
+startTest(function() {
+ return Promise.resolve()
+ .then(() => runTestSuite("cdma"))
+ .then(() => runTestSuite("wcdma"))
+
+ .catch(error => ok(false, "Promise reject: " + error))
+ .then(finish);
+});
+
diff --git a/dom/telephony/test/marionette/test_incoming_basic_operations.js b/dom/telephony/test/marionette/test_incoming_basic_operations.js
deleted file mode 100644
index 037df93f2d88..000000000000
--- a/dom/telephony/test/marionette/test_incoming_basic_operations.js
+++ /dev/null
@@ -1,123 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_TIMEOUT = 90000;
-MARIONETTE_HEAD_JS = 'head.js';
-
-const inNumber = "5555552222";
-const inInfo = gInCallStrPool(inNumber);
-var inCall;
-
-function incoming() {
- return gRemoteDial(inNumber)
- .then(call => inCall = call)
- .then(() => gCheckAll(null, [inCall], "", [], [inInfo.incoming]))
- .then(() => is(inCall.disconnectedReason, null));
-}
-
-function answer() {
- return gAnswer(inCall)
- .then(() => gCheckAll(inCall, [inCall], "", [], [inInfo.active]))
- .then(() => is(inCall.disconnectedReason, null));
-}
-
-function hold() {
- return gHold(inCall)
- .then(() => gCheckAll(null, [inCall], "", [], [inInfo.held]))
- .then(() => is(inCall.disconnectedReason, null));
-}
-
-function resume() {
- return gResume(inCall)
- .then(() => gCheckAll(inCall, [inCall], "", [], [inInfo.active]))
- .then(() => is(inCall.disconnectedReason, null));
-}
-
-function hangUp() {
- return gHangUp(inCall)
- .then(() => gCheckAll(null, [], "", [], []))
- .then(() => is(inCall.disconnectedReason, "NormalCallClearing"));
-}
-
-function remoteHangUp() {
- return gRemoteHangUp(inCall)
- .then(() => gCheckAll(null, [], "", [], []))
- .then(() => is(inCall.disconnectedReason, "NormalCallClearing"));
-}
-
-// Test cases.
-
-function testIncomingReject() {
- log("= testIncomingReject =");
- return incoming()
- .then(() => hangUp());
-}
-
-function testIncomingCancel() {
- log("= testIncomingCancel =");
- return incoming()
- .then(() => remoteHangUp());
-}
-
-function testIncomingAnswerHangUp() {
- log("= testIncomingAnswerHangUp =");
- return incoming()
- .then(() => answer())
- .then(() => hangUp());
-}
-
-function testIncomingAnswerRemoteHangUp() {
- log("= testIncomingAnswerRemoteHangUp =");
- return incoming()
- .then(() => answer())
- .then(() => remoteHangUp());
-}
-
-function testIncomingAnswerHoldHangUp() {
- log("= testIncomingAnswerHoldHangUp =");
- return incoming()
- .then(() => answer())
- .then(() => hold())
- .then(() => hangUp());
-}
-
-function testIncomingAnswerHoldRemoteHangUp() {
- log("= testIncomingAnswerHoldRemoteHangUp =");
- return incoming()
- .then(() => answer())
- .then(() => hold())
- .then(() => remoteHangUp());
-}
-
-function testIncomingAnswerHoldResumeHangUp() {
- log("= testIncomingAnswerHoldResumeHangUp =");
- return incoming()
- .then(() => answer())
- .then(() => hold())
- .then(() => resume())
- .then(() => hangUp());
-}
-
-function testIncomingAnswerHoldResumeRemoteHangUp() {
- log("= testIncomingAnswerHoldResumeRemoteHangUp =");
- return incoming()
- .then(() => answer())
- .then(() => hold())
- .then(() => resume())
- .then(() => remoteHangUp());
-}
-
-startTest(function() {
- Promise.resolve()
- .then(() => testIncomingReject())
- .then(() => testIncomingCancel())
- .then(() => testIncomingAnswerHangUp())
- .then(() => testIncomingAnswerRemoteHangUp())
- .then(() => testIncomingAnswerHoldHangUp())
- .then(() => testIncomingAnswerHoldRemoteHangUp())
- .then(() => testIncomingAnswerHoldResumeHangUp())
- .then(() => testIncomingAnswerHoldResumeRemoteHangUp())
-
- .catch(error => ok(false, "Promise reject: " + error))
- .then(finish);
-});
diff --git a/dom/telephony/test/marionette/test_modem_switch_tech.js b/dom/telephony/test/marionette/test_modem_switch_tech.js
index 565f528ec5c0..7af228cdae4d 100644
--- a/dom/telephony/test/marionette/test_modem_switch_tech.js
+++ b/dom/telephony/test/marionette/test_modem_switch_tech.js
@@ -39,7 +39,7 @@ var settings = [
startTest(function() {
let promise = settings.reduce((aPromise, aSetting) => {
- return aPromise.then(() => gChangeModemTech(aSetting.tech, aSetting.mask));
+ return aPromise.then(() => Modem.changeTech(aSetting.tech, aSetting.mask));
}, Promise.resolve());
return promise
@@ -47,7 +47,7 @@ startTest(function() {
.catch(error => ok(false, "Promise reject: " + error))
// Switch to the default modem tech
- .then(() => gChangeModemTech("wcdma", "gsm/wcdma"))
+ .then(() => Modem.changeTech("wcdma", "gsm/wcdma"))
.catch(error => ok(false, "Fetal Error: Promise reject: " + error))
.then(finish);
diff --git a/dom/telephony/test/marionette/test_outgoing_auto_hold.js b/dom/telephony/test/marionette/test_outgoing_auto_hold.js
index af07835d3063..7dca375920bd 100644
--- a/dom/telephony/test/marionette/test_outgoing_auto_hold.js
+++ b/dom/telephony/test/marionette/test_outgoing_auto_hold.js
@@ -37,7 +37,7 @@ function testAutoHoldCallFailed() {
const callNumber2 = "0900000012";
return Promise.resolve()
- .then(() => emulator.runCmd("gsm disable hold"))
+ .then(() => emulator.runCmd("telephony disable hold"))
.then(() => gDial(callNumber1))
.then(call => { outCall1 = call; })
.then(() => gRemoteAnswer(outCall1))
@@ -51,7 +51,7 @@ function testAutoHoldCallFailed() {
return gRemoteHangUpCalls([outCall2]);
}, () => log("The second |dial()| is rejected as expected."))
.then(() => gRemoteHangUpCalls([outCall1]))
- .then(() => emulator.runCmd("gsm enable hold"));
+ .then(() => emulator.runCmd("telephony enable hold"));
}
function testAutoHoldConferenceCall() {
@@ -87,7 +87,7 @@ startTest(function() {
.then(() => testAutoHoldConferenceCall())
.catch(error => {
ok(false, "Promise reject: " + error);
- emulator.runCmd("gsm enable hold");
+ emulator.runCmd("telephony enable hold");
})
.then(finish);
});
diff --git a/dom/telephony/test/marionette/test_outgoing_basic_operations.js b/dom/telephony/test/marionette/test_outgoing_basic_operations.js
deleted file mode 100644
index 97ae31f669d0..000000000000
--- a/dom/telephony/test/marionette/test_outgoing_basic_operations.js
+++ /dev/null
@@ -1,123 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_TIMEOUT = 90000;
-MARIONETTE_HEAD_JS = 'head.js';
-
-const outNumber = "5555551111";
-const outInfo = gOutCallStrPool(outNumber);
-var outCall;
-
-function outgoing() {
- return gDial(outNumber)
- .then(call => outCall = call)
- .then(() => gCheckAll(outCall, [outCall], "", [], [outInfo.ringing]))
- .then(() => is(outCall.disconnectedReason, null));
-}
-
-function answer() {
- return gRemoteAnswer(outCall)
- .then(() => gCheckAll(outCall, [outCall], "", [], [outInfo.active]))
- .then(() => is(outCall.disconnectedReason, null));
-}
-
-function hangUp() {
- return gHangUp(outCall)
- .then(() => gCheckAll(null, [], "", [], []))
- .then(() => is(outCall.disconnectedReason, "NormalCallClearing"));
-}
-
-function remoteHangUp() {
- return gRemoteHangUp(outCall)
- .then(() => gCheckAll(null, [], "", [], []))
- .then(() => is(outCall.disconnectedReason, "NormalCallClearing"));
-}
-
-function hold() {
- return gHold(outCall)
- .then(() => gCheckAll(null, [outCall], "", [], [outInfo.held]))
- .then(() => is(outCall.disconnectedReason, null));
-}
-
-function resume() {
- return gResume(outCall)
- .then(() => gCheckAll(outCall, [outCall], "", [], [outInfo.active]))
- .then(() => is(outCall.disconnectedReason, null));
-}
-
-// Test cases.
-
-function testOutgoingReject() {
- log("= testOutgoingReject =");
- return outgoing()
- .then(() => remoteHangUp());
-}
-
-function testOutgoingCancel() {
- log("= testOutgoingCancel =");
- return outgoing()
- .then(() => hangUp());
-}
-
-function testOutgoingAnswerHangUp() {
- log("= testOutgoingAnswerHangUp =");
- return outgoing()
- .then(() => answer())
- .then(() => hangUp());
-}
-
-function testOutgoingAnswerRemoteHangUp() {
- log("= testOutgoingAnswerRemoteHangUp =");
- return outgoing()
- .then(() => answer())
- .then(() => remoteHangUp());
-}
-
-function testOutgoingAnswerHoldHangUp() {
- log("= testOutgoingAnswerHoldHangUp =");
- return outgoing()
- .then(() => answer())
- .then(() => hold())
- .then(() => hangUp());
-}
-
-function testOutgoingAnswerHoldRemoteHangUp() {
- log("= testOutgoingAnswerHoldRemoteHangUp =");
- return outgoing()
- .then(() => answer())
- .then(() => hold())
- .then(() => remoteHangUp());
-}
-
-function testOutgoingAnswerHoldResumeHangUp() {
- log("= testOutgoingAnswerHoldResumeHangUp =");
- return outgoing()
- .then(() => answer())
- .then(() => hold())
- .then(() => resume())
- .then(() => hangUp());
-}
-
-function testOutgoingAnswerHoldResumeRemoteHangUp() {
- log("= testOutgoingAnswerHoldResumeRemoteHangUp =");
- return outgoing()
- .then(() => answer())
- .then(() => hold())
- .then(() => resume())
- .then(() => remoteHangUp());
-}
-
-startTest(function() {
- Promise.resolve()
- .then(() => testOutgoingReject())
- .then(() => testOutgoingCancel())
- .then(() => testOutgoingAnswerHangUp())
- .then(() => testOutgoingAnswerRemoteHangUp())
- .then(() => testOutgoingAnswerHoldHangUp())
- .then(() => testOutgoingAnswerHoldRemoteHangUp())
- .then(() => testOutgoingAnswerHoldResumeHangUp())
- .then(() => testOutgoingAnswerHoldResumeRemoteHangUp())
-
- .catch(error => ok(false, "Promise reject: " + error))
- .then(finish);
-});
diff --git a/dom/telephony/test/marionette/test_outgoing_busy.js b/dom/telephony/test/marionette/test_outgoing_busy.js
index 5c48acda8b25..1a77316db233 100644
--- a/dom/telephony/test/marionette/test_outgoing_busy.js
+++ b/dom/telephony/test/marionette/test_outgoing_busy.js
@@ -19,7 +19,7 @@ startTest(function() {
is(event.call.error.name, "BusyError");
is(event.call.disconnectedReason, "Busy");
});
- let p2 = emulator.runCmd("gsm busy " + outNumber);
+ let p2 = emulator.runCmd("telephony busy " + outNumber);
return Promise.all([p1, p2]);
})
.then(() => gCheckAll(null, [], "", [], []))
diff --git a/ipc/hal/DaemonSocketPDUHelpers.h b/ipc/hal/DaemonSocketPDUHelpers.h
index 1d7a0ae89407..3bd28c4f21df 100644
--- a/ipc/hal/DaemonSocketPDUHelpers.h
+++ b/ipc/hal/DaemonSocketPDUHelpers.h
@@ -1023,6 +1023,41 @@ public:
WarnAboutTrailingData();
return NS_OK;
}
+
+ template
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5, T6& aArg6) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
};
} // namespace DaemonSocketPDUHelpers
diff --git a/mobile/android/base/resources/layout/preference_search_tip.xml b/mobile/android/base/resources/layout/preference_search_tip.xml
index 0ff11e18cb50..e03b171b468a 100644
--- a/mobile/android/base/resources/layout/preference_search_tip.xml
+++ b/mobile/android/base/resources/layout/preference_search_tip.xml
@@ -2,14 +2,19 @@
-
+
+
+
+ android:paddingRight="6dip"
+ android:layout_weight="1"/>
-
+
+
+
diff --git a/mobile/android/base/webapp/Allocator.java b/mobile/android/base/webapp/Allocator.java
index 9f9786db27dd..e7a18bdef75c 100644
--- a/mobile/android/base/webapp/Allocator.java
+++ b/mobile/android/base/webapp/Allocator.java
@@ -11,7 +11,6 @@ import org.mozilla.gecko.GeckoAppShell;
import android.content.Context;
import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
import android.util.Log;
public class Allocator {
@@ -46,6 +45,8 @@ public class Allocator {
SharedPreferences mPrefs;
+ @SuppressWarnings("deprecation") // Suppressing deprecation notification for Context.MODE_MULTI_PROCESS until we
+ // reach a timeline for removal of the whole feature. (Bug 1171213)
protected Allocator(Context context) {
mPrefs = context.getSharedPreferences("webapps", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
}
diff --git a/mobile/android/chrome/content/CastingApps.js b/mobile/android/chrome/content/CastingApps.js
index 341628290492..4d8177823e36 100644
--- a/mobile/android/chrome/content/CastingApps.js
+++ b/mobile/android/chrome/content/CastingApps.js
@@ -65,6 +65,7 @@ var CastingApps = {
mirrorStopMenuId: -1,
_blocked: null,
_bound: null,
+ _interval: 120 * 1000, // 120 seconds
init: function ca_init() {
if (!this.isCastingEnabled()) {
@@ -78,8 +79,8 @@ var CastingApps = {
mediaPlayerDevice.init();
SimpleServiceDiscovery.registerDevice(mediaPlayerDevice);
- // Search for devices continuously every 120 seconds
- SimpleServiceDiscovery.search(120 * 1000);
+ // Search for devices continuously
+ SimpleServiceDiscovery.search(this._interval);
this._castMenuId = NativeWindow.contextmenus.add(
Strings.browser.GetStringFromName("contextmenu.sendToDevice"),
@@ -93,6 +94,8 @@ var CastingApps = {
Services.obs.addObserver(this, "Casting:Mirror", false);
Services.obs.addObserver(this, "ssdp-service-found", false);
Services.obs.addObserver(this, "ssdp-service-lost", false);
+ Services.obs.addObserver(this, "application-background", false);
+ Services.obs.addObserver(this, "application-foreground", false);
BrowserApp.deck.addEventListener("TabSelect", this, true);
BrowserApp.deck.addEventListener("pageshow", this, true);
@@ -195,15 +198,20 @@ var CastingApps = {
}
break;
case "ssdp-service-found":
- {
- this.serviceAdded(SimpleServiceDiscovery.findServiceForID(aData));
- break;
- }
+ this.serviceAdded(SimpleServiceDiscovery.findServiceForID(aData));
+ break;
case "ssdp-service-lost":
- {
- this.serviceLost(SimpleServiceDiscovery.findServiceForID(aData));
- break;
- }
+ this.serviceLost(SimpleServiceDiscovery.findServiceForID(aData));
+ break;
+ case "application-background":
+ // Turn off polling while in the background
+ this._interval = SimpleServiceDiscovery.search(0);
+ SimpleServiceDiscovery.stopSearch();
+ break;
+ case "application-foreground":
+ // Turn polling on when app comes back to foreground
+ SimpleServiceDiscovery.search(this._interval);
+ break;
}
},
diff --git a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
index 4b7e03c80aef..2dcf60ad88f1 100644
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -17,6 +17,7 @@ this.EXPORTED_SYMBOLS = [
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
@@ -458,5 +459,147 @@ this.BrowserTestUtils = {
tab.ownerDocument.defaultView.gBrowser.removeTab(tab);
}
});
- }
+ },
+
+ /**
+ * Crashes a remote browser tab and cleans up the generated minidumps.
+ * Resolves with the data from the .extra file (the crash annotations).
+ *
+ * @param (Browser) browser
+ * A remote element. Must not be null.
+ *
+ * @returns (Promise)
+ * @resolves An Object with key-value pairs representing the data from the
+ * crash report's extra file (if applicable).
+ */
+ crashBrowser: Task.async(function*(browser) {
+ let extra = {};
+ let KeyValueParser = {};
+ if (AppConstants.MOZ_CRASHREPORTER) {
+ Cu.import("resource://gre/modules/KeyValueParser.jsm", KeyValueParser);
+ }
+
+ if (!browser.isRemoteBrowser) {
+ throw new Error(" needs to be remote in order to crash");
+ }
+
+ /**
+ * Returns the directory where crash dumps are stored.
+ *
+ * @return nsIFile
+ */
+ function getMinidumpDirectory() {
+ let dir = Services.dirsvc.get('ProfD', Ci.nsIFile);
+ dir.append("minidumps");
+ return dir;
+ }
+
+ /**
+ * Removes a file from a directory. This is a no-op if the file does not
+ * exist.
+ *
+ * @param directory
+ * The nsIFile representing the directory to remove from.
+ * @param filename
+ * A string for the file to remove from the directory.
+ */
+ function removeFile(directory, filename) {
+ let file = directory.clone();
+ file.append(filename);
+ if (file.exists()) {
+ file.remove(false);
+ }
+ }
+
+ // This frame script is injected into the remote browser, and used to
+ // intentionally crash the tab. We crash by using js-ctypes and dereferencing
+ // a bad pointer. The crash should happen immediately upon loading this
+ // frame script.
+ let frame_script = () => {
+ const Cu = Components.utils;
+ Cu.import("resource://gre/modules/ctypes.jsm");
+
+ let dies = function() {
+ privateNoteIntentionalCrash();
+ let zero = new ctypes.intptr_t(8);
+ let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
+ badptr.contents
+ };
+
+ dump("\nEt tu, Brute?\n");
+ dies();
+ }
+
+ let crashCleanupPromise = new Promise((resolve, reject) => {
+ let observer = (subject, topic, data) => {
+ if (topic != "ipc:content-shutdown") {
+ return reject("Received incorrect observer topic: " + topic);
+ }
+ if (!(subject instanceof Ci.nsIPropertyBag2)) {
+ return reject("Subject did not implement nsIPropertyBag2");
+ }
+ // we might see this called as the process terminates due to previous tests.
+ // We are only looking for "abnormal" exits...
+ if (!subject.hasKey("abnormal")) {
+ dump("\nThis is a normal termination and isn't the one we are looking for...\n");
+ return;
+ }
+
+ let dumpID;
+ if ('nsICrashReporter' in Ci) {
+ dumpID = subject.getPropertyAsAString('dumpID');
+ if (!dumpID) {
+ return reject("dumpID was not present despite crash reporting " +
+ "being enabled");
+ }
+ }
+
+ if (dumpID) {
+ let minidumpDirectory = getMinidumpDirectory();
+ let extrafile = minidumpDirectory.clone();
+ extrafile.append(dumpID + '.extra');
+ if (extrafile.exists()) {
+ dump(`\nNo .extra file for dumpID: ${dumpID}\n`);
+ if (AppConstants.MOZ_CRASHREPORTER) {
+ extra = KeyValueParser.parseKeyValuePairsFromFile(extrafile);
+ } else {
+ dump('\nCrashReporter not enabled - will not return any extra data\n');
+ }
+ }
+
+ removeFile(minidumpDirectory, dumpID + '.dmp');
+ removeFile(minidumpDirectory, dumpID + '.extra');
+ }
+
+ Services.obs.removeObserver(observer, 'ipc:content-shutdown');
+ dump("\nCrash cleaned up\n");
+ resolve();
+ };
+
+ Services.obs.addObserver(observer, 'ipc:content-shutdown', false);
+ });
+
+ let aboutTabCrashedLoadPromise = new Promise((resolve, reject) => {
+ browser.addEventListener("AboutTabCrashedLoad", function onCrash() {
+ browser.removeEventListener("AboutTabCrashedLoad", onCrash, false);
+ dump("\nabout:tabcrashed loaded\n");
+ resolve();
+ }, false, true);
+ });
+
+ // This frame script will crash the remote browser as soon as it is
+ // evaluated.
+ let mm = browser.messageManager;
+ mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", false);
+
+ yield Promise.all([crashCleanupPromise, aboutTabCrashedLoadPromise]);
+
+ let gBrowser = browser.ownerDocument.defaultView.gBrowser;
+ let tab = gBrowser.getTabForBrowser(browser);
+ if (tab.getAttribute("crashed") != "true") {
+ throw new Error("Tab should be marked as crashed");
+ }
+
+ return extra;
+ }),
};
diff --git a/toolkit/content/tests/browser/browser_content_url_annotation.js b/toolkit/content/tests/browser/browser_content_url_annotation.js
index cd42f99b0b62..62667651ccc7 100644
--- a/toolkit/content/tests/browser/browser_content_url_annotation.js
+++ b/toolkit/content/tests/browser/browser_content_url_annotation.js
@@ -9,72 +9,6 @@
// Running this test in ASAN is slow.
requestLongerTimeout(2);
-/**
- * Returns a Promise that resolves once a remote has experienced
- * a crash. Resolves with the data from the .extra file (the crash annotations).
- *
- * @param browser
- * The that will crash
- * @return Promise
- */
-function crashBrowser(browser) {
- let kv = {};
- Cu.import("resource://gre/modules/KeyValueParser.jsm", kv);
- // This frame script is injected into the remote browser, and used to
- // intentionally crash the tab. We crash by using js-ctypes and dereferencing
- // a bad pointer. The crash should happen immediately upon loading this
- // frame script.
- let frame_script = () => {
- const Cu = Components.utils;
- Cu.import("resource://gre/modules/ctypes.jsm");
-
- let dies = function() {
- privateNoteIntentionalCrash();
- let zero = new ctypes.intptr_t(8);
- let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
- let crash = badptr.contents;
- };
-
- dump("Et tu, Brute?");
- dies();
- };
-
- function checkSubject(subject, data) {
- return subject instanceof Ci.nsIPropertyBag2 &&
- subject.hasKey("abnormal");
- };
- let crashPromise = TestUtils.topicObserved('ipc:content-shutdown',
- checkSubject);
- let crashDataPromise = crashPromise.then(([subject, data]) => {
- ok(subject instanceof Ci.nsIPropertyBag2);
-
- let dumpID;
- if ('nsICrashReporter' in Ci) {
- dumpID = subject.getPropertyAsAString('dumpID');
- ok(dumpID, "dumpID is present and not an empty string");
- }
-
- let extra = null;
- if (dumpID) {
- let minidumpDirectory = getMinidumpDirectory();
- let extrafile = minidumpDirectory.clone();
- extrafile.append(dumpID + '.extra');
- ok(extrafile.exists(), 'found .extra file');
- extra = kv.parseKeyValuePairsFromFile(extrafile);
- removeFile(minidumpDirectory, dumpID + '.dmp');
- removeFile(minidumpDirectory, dumpID + '.extra');
- }
-
- return extra;
- });
-
- // This frame script will crash the remote browser as soon as it is
- // evaluated.
- let mm = browser.messageManager;
- mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", false);
- return crashDataPromise;
-}
-
/**
* Removes a file from a directory. This is a no-op if the file does not
* exist.
@@ -130,7 +64,7 @@ add_task(function* test_content_url_annotation() {
yield promise;
// Crash the tab
- let annotations = yield crashBrowser(browser);
+ let annotations = yield BrowserTestUtils.crashBrowser(browser);
ok("URL" in annotations, "annotated a URL");
is(annotations.URL, redirect_url,
diff --git a/toolkit/mozapps/downloads/DownloadUtils.jsm b/toolkit/mozapps/downloads/DownloadUtils.jsm
index 9a106ef1cab4..2c4875947255 100644
--- a/toolkit/mozapps/downloads/DownloadUtils.jsm
+++ b/toolkit/mozapps/downloads/DownloadUtils.jsm
@@ -483,7 +483,7 @@ this.DownloadUtils = {
if (aBytes === Infinity) {
aBytes = "Infinity";
} else {
- if (Intl) {
+ if (typeof Intl != "undefined") {
aBytes = getLocaleNumberFormat(fractionDigits)
.format(aBytes);
} else if (gDecimalSymbol != ".") {
diff --git a/toolkit/themes/shared/in-content/common.inc.css b/toolkit/themes/shared/in-content/common.inc.css
index c3c77d8995bd..1b19a93bc217 100644
--- a/toolkit/themes/shared/in-content/common.inc.css
+++ b/toolkit/themes/shared/in-content/common.inc.css
@@ -406,13 +406,11 @@ xul|button[type="menu"] > xul|menupopup xul|menuseparator {
/* textboxes */
-*|textbox {
+html|input[type="text"],
+html|textarea,
+xul|textbox {
-moz-appearance: none;
- height: 30px;
color: var(--in-content-text-color);
- line-height: 20px;
- padding-right: 10px;
- padding-left: 10px;
border: 1px solid var(--in-content-box-border-color);
-moz-border-top-colors: none !important;
-moz-border-right-colors: none !important;
@@ -422,12 +420,27 @@ xul|button[type="menu"] > xul|menupopup xul|menuseparator {
background-color: var(--in-content-box-background);
}
-html|textbox:focus,
+xul|textbox {
+ min-height: 30px;
+ padding-right: 10px;
+ padding-left: 10px;
+}
+
+html|input[type="text"],
+html|textarea {
+ font-family: inherit;
+ font-size: inherit;
+ padding: 5px 10px;
+}
+
+html|input[type="text"]:focus,
+html|textarea:focus,
xul|textbox[focused] {
border-color: var(--in-content-border-focus);
}
-html|textbox:disabled,
+html|input[type="text"]:disabled,
+html|textarea:disabled,
xul|textbox[disabled="true"] {
opacity: 0.5;
}