diff --git a/browser/base/content/browser-media.js b/browser/base/content/browser-media.js index 36b2c019a5ec..7577e9cbf8da 100644 --- a/browser/base/content/browser-media.js +++ b/browser/base/content/browser-media.js @@ -296,7 +296,7 @@ let gDecoderDoctorHandler = { let existing = formatsInPref.split(",").map(String.trim); // Keep given formats that were not already recorded. let newbies = formats.split(",").map(String.trim) - .filter(x => existing.includes(x)); + .filter(x => !existing.includes(x)); // And rewrite pref with the added new formats (if any). if (newbies.length) { Services.prefs.setCharPref(formatsPref, diff --git a/browser/components/preferences/connection.xul b/browser/components/preferences/connection.xul index 262efba07997..a3f0d082a9af 100644 --- a/browser/components/preferences/connection.xul +++ b/browser/components/preferences/connection.xul @@ -14,7 +14,12 @@ dlgbuttons="accept,cancel,help" onbeforeaccept="return gConnectionsDialog.beforeAccept();" onload="gConnectionsDialog.checkForSystemProxy();" - ondialoghelp="openPrefsHelp()"> + ondialoghelp="openPrefsHelp()" +#ifdef XP_MACOSX + style="width: &window.macWidth2; !important;"> +#else + style="width: &window.width2; !important;"> +#endif diff --git a/browser/components/preferences/jar.mn b/browser/components/preferences/jar.mn index 84c5c10de4b8..6287c38ccd0d 100644 --- a/browser/components/preferences/jar.mn +++ b/browser/components/preferences/jar.mn @@ -10,7 +10,7 @@ browser.jar: * content/browser/preferences/colors.xul * content/browser/preferences/cookies.xul content/browser/preferences/cookies.js - content/browser/preferences/connection.xul +* content/browser/preferences/connection.xul content/browser/preferences/connection.js content/browser/preferences/donottrack.xul * content/browser/preferences/fonts.xul diff --git a/browser/locales/en-US/chrome/browser/preferences/connection.dtd b/browser/locales/en-US/chrome/browser/preferences/connection.dtd index 4ce7969378ae..850964a0fa7c 100644 --- a/browser/locales/en-US/chrome/browser/preferences/connection.dtd +++ b/browser/locales/en-US/chrome/browser/preferences/connection.dtd @@ -4,6 +4,8 @@ + + diff --git a/browser/modules/SitePermissions.jsm b/browser/modules/SitePermissions.jsm index e6714ae1b142..389fd599ee64 100644 --- a/browser/modules/SitePermissions.jsm +++ b/browser/modules/SitePermissions.jsm @@ -24,6 +24,8 @@ this.SitePermissions = { * * To receive a more detailed, albeit less performant listing see * SitePermissions.getPermissionDetailsByURI(). + * + * install addon permission is excluded, check bug 1303108 */ getAllByURI: function (aURI) { let result = []; @@ -37,6 +39,10 @@ this.SitePermissions = { // filter out unknown permissions if (gPermissionObject[permission.type]) { + // XXX Bug 1303108 - Control Center should only show non-default permissions + if (permission.type == "install") { + continue; + } result.push({ id: permission.type, state: permission.capability, diff --git a/browser/modules/test/xpcshell/test_SitePermissions.js b/browser/modules/test/xpcshell/test_SitePermissions.js index 8823a54c556d..808d965991ae 100644 --- a/browser/modules/test/xpcshell/test_SitePermissions.js +++ b/browser/modules/test/xpcshell/test_SitePermissions.js @@ -45,6 +45,11 @@ add_task(function* testGetAllByURI() { SitePermissions.remove(uri, "camera"); SitePermissions.remove(uri, "desktop-notification"); Assert.deepEqual(SitePermissions.getAllByURI(uri), []); + + // XXX Bug 1303108 - Control Center should only show non-default permissions + SitePermissions.set(uri, "addon", SitePermissions.BLOCK); + Assert.deepEqual(SitePermissions.getAllByURI(uri), []); + SitePermissions.remove(uri, "addon"); }); add_task(function* testGetPermissionDetailsByURI() { diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm index 0c351d219835..fc38a6abf34d 100644 --- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm +++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm @@ -28,9 +28,11 @@ this.Preferences = { ["paneAdvanced", "generalTab"], ["paneAdvanced", "dataChoicesTab"], ["paneAdvanced", "networkTab"], + ["paneAdvanced", "networkTab", connectionDialog], ["paneAdvanced", "updateTab"], ["paneAdvanced", "encryptionTab"], ["paneAdvanced", "encryptionTab", certManager], + ["paneAdvanced", "encryptionTab", deviceManager], ]; for (let [primary, advanced, customFn] of panes) { let configName = primary.replace(/^pane/, "prefs") + (advanced ? "-" + advanced : ""); @@ -99,8 +101,20 @@ function* DNTDialog(aBrowser) { }); } +function* connectionDialog(aBrowser) { + yield ContentTask.spawn(aBrowser, null, function* () { + content.document.getElementById("connectionSettings").click(); + }); +} + function* certManager(aBrowser) { yield ContentTask.spawn(aBrowser, null, function* () { content.document.getElementById("viewCertificatesButton").click(); }); } + +function* deviceManager(aBrowser) { + yield ContentTask.spawn(aBrowser, null, function* () { + content.document.getElementById("viewSecurityDevicesButton").click(); + }); +} diff --git a/build/autoconf/android.m4 b/build/autoconf/android.m4 index 53a2e3b4868c..914818b92619 100644 --- a/build/autoconf/android.m4 +++ b/build/autoconf/android.m4 @@ -221,8 +221,8 @@ fi ]) dnl Configure an Android SDK. -dnl Arg 1: target SDK version, like 22. -dnl Arg 2: build tools version, like 22.0.1. +dnl Arg 1: target SDK version, like 23. +dnl Arg 2: list of build-tools versions, like "23.0.3 23.0.1". AC_DEFUN([MOZ_ANDROID_SDK], [ @@ -254,12 +254,20 @@ case "$target" in fi AC_MSG_RESULT([$android_sdk]) - android_build_tools="$android_sdk_root"/build-tools/$2 - AC_MSG_CHECKING([for Android build-tools version $2]) - if test -d "$android_build_tools" -a -f "$android_build_tools/aapt"; then - AC_MSG_RESULT([$android_build_tools]) - else - AC_MSG_ERROR([You must install the Android build-tools version $2. Try |mach bootstrap|. (Looked for $android_build_tools)]) + AC_MSG_CHECKING([for Android build-tools]) + android_build_tools_base="$android_sdk_root"/build-tools + android_build_tools_version="" + for version in $2; do + android_build_tools="$android_build_tools_base"/$version + if test -d "$android_build_tools" -a -f "$android_build_tools/aapt"; then + android_build_tools_version=$version + AC_MSG_RESULT([$android_build_tools]) + break + fi + done + if test "$android_build_tools_version" == ""; then + version=$(echo $2 | cut -d" " -f1) + AC_MSG_ERROR([You must install the Android build-tools version $version. Try |mach bootstrap|. (Looked for "$android_build_tools_base"/$version)]) fi MOZ_PATH_PROG(ZIPALIGN, zipalign, :, [$android_build_tools]) @@ -309,7 +317,7 @@ case "$target" in ANDROID_SDK="${android_sdk}" ANDROID_SDK_ROOT="${android_sdk_root}" ANDROID_TOOLS="${android_tools}" - ANDROID_BUILD_TOOLS_VERSION="$2" + ANDROID_BUILD_TOOLS_VERSION="$android_build_tools_version" AC_DEFINE_UNQUOTED(ANDROID_TARGET_SDK,$ANDROID_TARGET_SDK) AC_SUBST(ANDROID_TARGET_SDK) AC_SUBST(ANDROID_SDK_ROOT) diff --git a/devtools/client/responsive.html/manager.js b/devtools/client/responsive.html/manager.js index 158a9b856b70..5146561011fe 100644 --- a/devtools/client/responsive.html/manager.js +++ b/devtools/client/responsive.html/manager.js @@ -305,8 +305,9 @@ ResponsiveUI.prototype = { init: Task.async(function* () { let ui = this; - // Watch for tab close so we can clean up RDM synchronously + // Watch for tab close and window close so we can clean up RDM synchronously this.tab.addEventListener("TabClose", this); + this.browserWindow.addEventListener("unload", this); // Swap page content from the current tab into a viewport within RDM this.swap = swapToInnerBrowser({ @@ -348,7 +349,8 @@ ResponsiveUI.prototype = { // If our tab is about to be closed, there's not enough time to exit // gracefully, but that shouldn't be a problem since the tab will go away. // So, skip any yielding when we're about to close the tab. - let isTabClosing = options && options.reason == "TabClose"; + let isWindowClosing = options && options.reason === "unload"; + let isTabClosing = (options && options.reason === "TabClose") || isWindowClosing; // Ensure init has finished before starting destroy if (!isTabClosing) { @@ -356,6 +358,7 @@ ResponsiveUI.prototype = { } this.tab.removeEventListener("TabClose", this); + this.browserWindow.removeEventListener("unload", this); this.toolWindow.removeEventListener("message", this); if (!isTabClosing) { @@ -381,8 +384,10 @@ ResponsiveUI.prototype = { } this.client = this.emulationFront = null; - // Undo the swap and return the content back to a normal tab - swap.stop(); + if (!isWindowClosing) { + // Undo the swap and return the content back to a normal tab + swap.stop(); + } this.destroyed = true; @@ -407,6 +412,7 @@ ResponsiveUI.prototype = { case "message": this.handleMessage(event); break; + case "unload": case "TabClose": ResponsiveUIManager.closeIfNeeded(browserWindow, tab, { reason: event.type, diff --git a/devtools/client/responsive.html/test/browser/browser.ini b/devtools/client/responsive.html/test/browser/browser.ini index 2928ac815240..ddcb539522ce 100644 --- a/devtools/client/responsive.html/test/browser/browser.ini +++ b/devtools/client/responsive.html/test/browser/browser.ini @@ -8,6 +8,7 @@ support-files = doc_page_state.html geolocation.html head.js + touch.html !/devtools/client/commandline/test/helpers.js !/devtools/client/framework/test/shared-head.js !/devtools/client/framework/test/shared-redux-head.js @@ -36,3 +37,4 @@ support-files = [browser_toolbox_swap_browsers.js] [browser_touch_simulation.js] [browser_viewport_basics.js] +[browser_window_close.js] diff --git a/devtools/client/responsive.html/test/browser/browser_touch_simulation.js b/devtools/client/responsive.html/test/browser/browser_touch_simulation.js index 8c50deb0784d..bdebe37cf06c 100644 --- a/devtools/client/responsive.html/test/browser/browser_touch_simulation.js +++ b/devtools/client/responsive.html/test/browser/browser_touch_simulation.js @@ -5,15 +5,171 @@ // Test global touch simulation button -const TEST_URL = "data:text/html;charset=utf-8,"; +const TEST_URL = `${URL_ROOT}touch.html`; +const PREF_DOM_META_VIEWPORT_ENABLED = "dom.meta-viewport.enabled"; addRDMTask(TEST_URL, function* ({ ui }) { - let { store, document } = ui.toolWindow; - let touchButton = document.querySelector("#global-touch-simulation-button"); + yield waitBootstrap(ui); + yield testWithNoTouch(ui); + yield enableTouchSimulation(ui); + yield testWithTouch(ui); + yield testWithMetaViewportEnabled(ui); + yield testWithMetaViewportDisabled(ui); + testTouchButton(ui); +}); - // Wait until the viewport has been added - yield waitUntilState(store, state => state.viewports.length == 1); - yield waitForFrameLoad(ui, TEST_URL); +function* testWithNoTouch(ui) { + yield injectEventUtils(ui); + yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () { + let { EventUtils } = content; + + let div = content.document.querySelector("div"); + let x = 0, y = 0; + + info("testWithNoTouch: Initial test parameter and mouse mouse outside div"); + x = -1; y = -1; + yield EventUtils.synthesizeMouse(div, x, y, + { type: "mousemove", isSynthesized: false }, content); + div.style.transform = "none"; + div.style.backgroundColor = ""; + + info("testWithNoTouch: Move mouse into the div element"); + yield EventUtils.synthesizeMouseAtCenter(div, + { type: "mousemove", isSynthesized: false }, content); + is(div.style.backgroundColor, "red", "mouseenter or mouseover should work"); + + info("testWithNoTouch: Drag the div element"); + yield EventUtils.synthesizeMouseAtCenter(div, + { type: "mousedown", isSynthesized: false }, content); + x = 100; y = 100; + yield EventUtils.synthesizeMouse(div, x, y, + { type: "mousemove", isSynthesized: false }, content); + is(div.style.transform, "none", "touchmove shouldn't work"); + yield EventUtils.synthesizeMouse(div, x, y, + { type: "mouseup", isSynthesized: false }, content); + + info("testWithNoTouch: Move mouse out of the div element"); + x = -1; y = -1; + yield EventUtils.synthesizeMouse(div, x, y, + { type: "mousemove", isSynthesized: false }, content); + is(div.style.backgroundColor, "blue", "mouseout or mouseleave should work"); + + info("testWithNoTouch: Click the div element"); + yield EventUtils.synthesizeClick(div); + is(div.dataset.isDelay, "false", + "300ms delay between touch events and mouse events should not work"); + }); +} + +function* testWithTouch(ui) { + yield injectEventUtils(ui); + + yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () { + let { EventUtils } = content; + + let div = content.document.querySelector("div"); + let x = 0, y = 0; + + info("testWithTouch: Initial test parameter and mouse mouse outside div"); + x = -1; y = -1; + yield EventUtils.synthesizeMouse(div, x, y, + { type: "mousemove", isSynthesized: false }, content); + div.style.transform = "none"; + div.style.backgroundColor = ""; + + info("testWithTouch: Move mouse into the div element"); + yield EventUtils.synthesizeMouseAtCenter(div, + { type: "mousemove", isSynthesized: false }, content); + isnot(div.style.backgroundColor, "red", + "mouseenter or mouseover should not work"); + + info("testWithTouch: Drag the div element"); + yield EventUtils.synthesizeMouseAtCenter(div, + { type: "mousedown", isSynthesized: false }, content); + x = 100; y = 100; + yield EventUtils.synthesizeMouse(div, x, y, + { type: "mousemove", isSynthesized: false }, content); + isnot(div.style.transform, "none", "touchmove should work"); + yield EventUtils.synthesizeMouse(div, x, y, + { type: "mouseup", isSynthesized: false }, content); + + info("testWithTouch: Move mouse out of the div element"); + x = -1; y = -1; + yield EventUtils.synthesizeMouse(div, x, y, + { type: "mousemove", isSynthesized: false }, content); + isnot(div.style.backgroundColor, "blue", + "mouseout or mouseleave should not work"); + }); +} + +function* testWithMetaViewportEnabled(ui) { + yield SpecialPowers.pushPrefEnv({set: [[PREF_DOM_META_VIEWPORT_ENABLED, true]]}); + + yield injectEventUtils(ui); + + yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () { + let { synthesizeClick } = content.EventUtils; + + let meta = content.document.querySelector("meta[name=viewport]"); + let div = content.document.querySelector("div"); + div.dataset.isDelay = "false"; + + info("testWithMetaViewportEnabled: " + + "click the div element with "); + meta.content = ""; + yield synthesizeClick(div); + is(div.dataset.isDelay, "true", + "300ms delay between touch events and mouse events should work"); + + info("testWithMetaViewportEnabled: " + + "click the div element with " + + ""); + meta.content = "user-scalable=no"; + yield synthesizeClick(div); + is(div.dataset.isDelay, "false", + "300ms delay between touch events and mouse events should not work"); + + info("testWithMetaViewportEnabled: " + + "click the div element with " + + ""); + meta.content = "minimum-scale=maximum-scale"; + yield synthesizeClick(div); + is(div.dataset.isDelay, "false", + "300ms delay between touch events and mouse events should not work"); + + info("testWithMetaViewportEnabled: " + + "click the div element with " + + ""); + meta.content = "width=device-width"; + yield synthesizeClick(div); + is(div.dataset.isDelay, "false", + "300ms delay between touch events and mouse events should not work"); + }); +} + +function* testWithMetaViewportDisabled(ui) { + yield SpecialPowers.pushPrefEnv({set: [[PREF_DOM_META_VIEWPORT_ENABLED, false]]}); + + yield injectEventUtils(ui); + + yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () { + let { synthesizeClick } = content.EventUtils; + + let meta = content.document.querySelector("meta[name=viewport]"); + let div = content.document.querySelector("div"); + div.dataset.isDelay = "false"; + + info("testWithMetaViewportDisabled: click the div with "); + meta.content = ""; + yield synthesizeClick(div); + is(div.dataset.isDelay, "true", + "300ms delay between touch events and mouse events should work"); + }); +} + +function testTouchButton(ui) { + let { document } = ui.toolWindow; + let touchButton = document.querySelector("#global-touch-simulation-button"); ok(!touchButton.classList.contains("active"), "Touch simulation is not active by default."); @@ -22,4 +178,63 @@ addRDMTask(TEST_URL, function* ({ ui }) { ok(touchButton.classList.contains("active"), "Touch simulation is started on click."); -}); + + touchButton.click(); + + ok(!touchButton.classList.contains("active"), + "Touch simulation is stopped on click."); +} + +function* waitBootstrap(ui) { + let { store } = ui.toolWindow; + + yield waitUntilState(store, state => state.viewports.length == 1); + yield waitForFrameLoad(ui, TEST_URL); +} + +function* injectEventUtils(ui) { + yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () { + if ("EventUtils" in content) { + return; + } + + let EventUtils = content.EventUtils = {}; + + EventUtils.window = {}; + EventUtils.parent = EventUtils.window; + /* eslint-disable camelcase */ + EventUtils._EU_Ci = Components.interfaces; + EventUtils._EU_Cc = Components.classes; + /* eslint-enable camelcase */ + // EventUtils' `sendChar` function relies on the navigator to synthetize events. + EventUtils.navigator = content.navigator; + EventUtils.KeyboardEvent = content.KeyboardEvent; + + EventUtils.synthesizeClick = element => new Promise(resolve => { + element.addEventListener("click", function onClick() { + element.removeEventListener("click", onClick); + resolve(); + }); + + EventUtils.synthesizeMouseAtCenter(element, + { type: "mousedown", isSynthesized: false }, content); + EventUtils.synthesizeMouseAtCenter(element, + { type: "mouseup", isSynthesized: false }, content); + }); + + Services.scriptloader.loadSubScript( + "chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils); + }); +} + +const enableTouchSimulation = ui => new Promise( + Task.async(function* (resolve) { + let browser = ui.getViewportBrowser(); + + browser.addEventListener("mozbrowserloadend", function onLoad() { + browser.removeEventListener("mozbrowserloadend", onLoad); + resolve(); + }); + + yield ui.updateTouchSimulation(true); + })); diff --git a/devtools/client/responsive.html/test/browser/browser_window_close.js b/devtools/client/responsive.html/test/browser/browser_window_close.js new file mode 100644 index 000000000000..29d9d1e344df --- /dev/null +++ b/devtools/client/responsive.html/test/browser/browser_window_close.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(function* () { + let newWindowPromise = BrowserTestUtils.waitForNewWindow(); + window.open("data:text/html;charset=utf-8,", "_blank"); + let newWindow = yield newWindowPromise; + + newWindow.focus(); + yield once(newWindow.gBrowser, "load", true); + + let tab = newWindow.gBrowser.selectedTab; + yield openRDM(tab); + + // Close the window on a tab with an active responsive design UI and + // wait for the UI to gracefully shutdown. This has leaked the window + // in the past. + ok(ResponsiveUIManager.isActiveForTab(tab), + "ResponsiveUI should be active for tab when the window is closed"); + let offPromise = once(ResponsiveUIManager, "off"); + yield BrowserTestUtils.closeWindow(newWindow); + yield offPromise; +}); diff --git a/devtools/client/responsive.html/test/browser/touch.html b/devtools/client/responsive.html/test/browser/touch.html new file mode 100644 index 000000000000..98aeac68fde4 --- /dev/null +++ b/devtools/client/responsive.html/test/browser/touch.html @@ -0,0 +1,86 @@ + + + + +