Merge fx-team to m-c a=merge CLOSED TREE

This commit is contained in:
Wes Kocher 2016-01-05 16:34:06 -08:00
commit d2a275509a
55 changed files with 1119 additions and 248 deletions

View File

@ -66,23 +66,36 @@ AlertsService.prototype = {
},
// nsIAlertsService
showAlert: function(aAlert, aAlertListener) {
if (!aAlert) {
return;
}
cpmm.sendAsyncMessage(kMessageAlertNotificationSend, {
imageURL: aAlert.imageURL,
title: aAlert.title,
text: aAlert.text,
clickable: aAlert.textClickable,
cookie: aAlert.cookie,
listener: aAlertListener,
id: aAlert.name,
dir: aAlert.dir,
lang: aAlert.lang,
dataStr: aAlert.data,
inPrivateBrowsing: aAlert.inPrivateBrowsing
});
},
showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable,
aCookie, aAlertListener, aName, aBidi,
aLang, aDataStr, aPrincipal,
aInPrivateBrowsing) {
cpmm.sendAsyncMessage(kMessageAlertNotificationSend, {
imageURL: aImageUrl,
title: aTitle,
text: aText,
clickable: aTextClickable,
cookie: aCookie,
listener: aAlertListener,
id: aName,
dir: aBidi,
lang: aLang,
dataStr: aDataStr,
inPrivateBrowsing: aInPrivateBrowsing
});
let alert = Cc["@mozilla.org/alert-notification;1"].
createInstance(Ci.nsIAlertNotification);
alert.init(aName, aImageUrl, aTitle, aText, aTextClickable, aCookie,
aBidi, aLang, aDataStr, aPrincipal, aInPrivateBrowsing);
this.showAlert(alert, aAlertListener);
},
closeAlert: function(aName) {

View File

@ -739,8 +739,6 @@ HistoryMenu.prototype = {
return;
}
let enabled = PlacesUIUtils.shouldEnableTabsFromOtherComputersMenuitem();
menuitem.setAttribute("disabled", !enabled);
menuitem.setAttribute("hidden", false);
},

View File

@ -803,6 +803,15 @@ BrowserGlue.prototype = {
this._sanitizer.onStartup();
// check if we're in safe mode
if (Services.appinfo.inSafeMode) {
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1231112#c7 . We need to
// register the observer early if we have to migrate tab groups
let currentUIVersion = 0;
try {
currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
} catch(ex) {}
if (currentUIVersion < 35) {
this._maybeMigrateTabGroups();
}
Services.ww.openWindow(null, "chrome://browser/content/safeMode.xul",
"_blank", "chrome,centerscreen,modal,resizable=no", null);
}
@ -2241,7 +2250,8 @@ BrowserGlue.prototype = {
this._notifyNotificationsUpgrade().catch(Cu.reportError);
}
if (currentUIVersion < 35) {
// Only do this outside of safe mode, because in safe mode we do this earlier.
if (currentUIVersion < 35 && !Services.appinfo.inSafeMode) {
this._maybeMigrateTabGroups();
}

View File

@ -556,7 +556,8 @@ var WindowListener = {
buttonNode.accessKey = paused ? this._getString("infobar_button_resume_accesskey") :
this._getString("infobar_button_pause_accesskey");
return true;
}
},
type: "pause"
},
{
label: this._getString("infobar_button_stop_label"),
@ -565,7 +566,8 @@ var WindowListener = {
callback: () => {
this._hideBrowserSharingInfoBar();
LoopUI.MozLoopService.hangupAllChatWindows();
}
},
type: "stop"
}]
);

View File

@ -21,6 +21,11 @@
border-radius: 0;
}
/* Hide Pause/Resume button until the functionality is complete */
notification[value="loop-sharing-notification"] .notification-button[type="pause"] {
display:none;
}
notification[value="loop-sharing-notification"].paused .notification-button {
background: #57bd35;
}

View File

@ -192,6 +192,11 @@
text-shadow: none;
}
/* Hide Pause/Resume button until the functionality is complete */
notification[value="loop-sharing-notification"] .notification-button[type="pause"] {
display:none;
}
notification[value="loop-sharing-notification"].paused .notification-button {
background-color: #57bd35;
color: #fff;

View File

@ -1440,6 +1440,10 @@ richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon
background-color: Window;
}
#sidebar-header > .close-icon:not(:hover):-moz-lwtheme-brighttext {
background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
}
.browserContainer > findbar {
background-color: -moz-dialog;
color: -moz-DialogText;

View File

@ -4,6 +4,8 @@
%include ../shared/devedition.inc.css
:root[devtoolstheme="dark"] .findbar-closebutton:not(:hover),
:root[devtoolstheme="dark"] #sidebar-header > .close-icon:not(:hover),
.tab-close-button[visuallyselected]:not(:hover) {
background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
}
@ -76,8 +78,9 @@
border-top-width: 0 !important;
}
/* Prevent devedition foreground color from seeping into the sidebar-box (since
* its background colors aren't affected by the devedition theme) */
#sidebar-box {
color: initial;
/* Fix the bad-looking text-shadow in the sidebar header: */
.sidebar-header,
#sidebar-header {
text-shadow: none;
}

View File

@ -52,8 +52,8 @@
@media (-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
.sidebar-header,
#sidebar-header {
.sidebar-header:not(:-moz-lwtheme),
#sidebar-header:not(:-moz-lwtheme) {
background-color: #EEF3FA;
}

View File

@ -1872,6 +1872,18 @@ richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon
border: none;
}
@media not all and (min-resolution: 1.1dppx) {
#sidebar-header > .close-icon:-moz-lwtheme-brighttext {
list-style-image: url("chrome://global/skin/icons/close-inverted.png");
}
}
@media (min-resolution: 1.1dppx) {
#sidebar-header > .close-icon:-moz-lwtheme-brighttext {
list-style-image: url("chrome://global/skin/icons/close-inverted@2x.png");
}
}
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {

View File

@ -107,6 +107,7 @@
}
:root[devtoolstheme="dark"] .findbar-closebutton,
:root[devtoolstheme="dark"] #sidebar-header > .close-icon,
/* Tab styling - make sure to use an inverted icon for the selected tab
(brighttext only covers the unselected tabs) */
.tab-close-button[visuallyselected=true] {
@ -115,6 +116,7 @@
@media (min-resolution: 1.1dppx) {
:root[devtoolstheme="dark"] .findbar-closebutton,
:root[devtoolstheme="dark"] #sidebar-header > .close-icon,
.tab-close-button[visuallyselected=true] {
list-style-image: url("chrome://global/skin/icons/close-inverted@2x.png");
}
@ -254,6 +256,14 @@
border-right: none !important;
}
/* The sidebar header has no background now that the background of the #browser-panel
* has no image and is transparent. Fix: */
.sidebar-header:-moz-lwtheme,
#sidebar-header {
background-color: var(--chrome-background-color);
color: var(--chrome-color);
}
@media (-moz-os-version: windows-vista),
(-moz-os-version: windows-win7),
(-moz-os-version: windows-win8) {

99
devtools/bootstrap.js vendored Normal file
View File

@ -0,0 +1,99 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cu = Components.utils;
const Ci = Components.interfaces;
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
// Helper to listen to a key on all windows
function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) {
let keyListener = function (event) {
if (event.ctrlKey == !!ctrlKey &&
event.altKey == !!altKey &&
event.keyCode === keyCode) {
callback(event);
// Call preventDefault to avoid duplicated events when
// doing the key stroke within a tab.
event.preventDefault();
}
};
let observer = function (window, topic, data) {
// Listen on keyup to call keyListener only once per stroke
if (topic === "domwindowopened") {
window.addEventListener("keyup", keyListener);
} else {
window.removeEventListener("keyup", keyListener);
}
};
return {
start: function () {
// Automatically process already opened windows
let e = Services.ww.getWindowEnumerator();
while (e.hasMoreElements()) {
let window = e.getNext();
observer(window, "domwindowopened", null);
}
// And listen for new ones to come
Services.ww.registerNotification(observer);
},
stop: function () {
Services.ww.unregisterNotification(observer);
let e = Services.ww.getWindowEnumerator();
while (e.hasMoreElements()) {
let window = e.getNext();
observer(window, "domwindowclosed", null);
}
}
};
};
let getTopLevelWindow = function (window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
};
function reload(event) {
// We automatically reload the toolbox if we are on a browser tab
// with a toolbox already opened
let top = getTopLevelWindow(event.view)
let isBrowser = top.location.href.includes("/browser.xul") && top.gDevToolsBrowser;
let reloadToolbox = false;
if (isBrowser && top.gDevToolsBrowser.hasToolboxOpened) {
reloadToolbox = top.gDevToolsBrowser.hasToolboxOpened(top);
}
dump("Reload DevTools. (reload-toolbox:"+reloadToolbox+")\n");
// Invalidate xul cache in order to see changes made to chrome:// files
Services.obs.notifyObservers(null, "startupcache-invalidate", null);
// Ask the loader to update itself and reopen the toolbox if needed
const {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {});
devtools.reload(reloadToolbox);
}
let listener;
function startup() {
dump("DevTools addon started.\n");
listener = new MultiWindowKeyListener({
keyCode: Ci.nsIDOMKeyEvent.DOM_VK_R, ctrlKey: true, altKey: true,
callback: reload
});
listener.start();
}
function shutdown() {
listener.stop();
listener = null;
}
function install() {}
function uninstall() {}

6
devtools/chrome.manifest Normal file
View File

@ -0,0 +1,6 @@
content devtools client/
skin devtools classic/1.0 client/themes/
resource devtools .
content webide client/webide/content/
skin webide classic/1.0 client/webide/themes/

View File

@ -18,7 +18,7 @@ const CALL_STACK_PAGE_SIZE = 25; // frames
const EVENTS = {
// When the debugger's source editor instance finishes loading or unloading.
EDITOR_LOADED: "Debugger:EditorLoaded",
EDITOR_UNLOADED: "Debugger:EditorUnoaded",
EDITOR_UNLOADED: "Debugger:EditorUnloaded",
// When new sources are received from the debugger server.
NEW_SOURCE: "Debugger:NewSource",

View File

@ -1161,6 +1161,16 @@ var gDevToolsBrowser = {
};
},
hasToolboxOpened: function(win) {
let tab = win.gBrowser.selectedTab;
for (let [target, toolbox] of gDevTools._toolboxes) {
if (target.tab == tab) {
return true;
}
}
return false;
},
/**
* Update the "Toggle Tools" checkbox in the developer tools menu. This is
* called when a toolbox is created or destroyed.
@ -1168,13 +1178,7 @@ var gDevToolsBrowser = {
_updateMenuCheckbox: function DT_updateMenuCheckbox() {
for (let win of gDevToolsBrowser._trackedBrowserWindows) {
let hasToolbox = false;
if (TargetFactory.isKnownTab(win.gBrowser.selectedTab)) {
let target = TargetFactory.forTab(win.gBrowser.selectedTab);
if (gDevTools._toolboxes.has(target)) {
hasToolbox = true;
}
}
let hasToolbox = gDevToolsBrowser.hasToolboxOpened(win);
let broadcaster = win.document.getElementById("devtoolsMenuBroadcaster_DevToolbox");
if (hasToolbox) {

View File

@ -51,9 +51,8 @@ var TreeView = React.createClass({
}
return (
DOM.div({className: "domTable", cellPadding: 0, cellSpacing: 0,
onClick: this.onClick},
children
DOM.div({className: "domTable", cellPadding: 0, cellSpacing: 0},
children
)
);
},
@ -151,8 +150,9 @@ var TreeNode = React.createFactory(React.createClass({
}
return (
DOM.div({className: classNames.join(" "), onClick: this.onClick},
DOM.span({className: "memberLabelCell"},
DOM.div({className: classNames.join(" ")},
DOM.span({className: "memberLabelCell", onClick: this.onClick},
DOM.span({className: "memberIcon"}),
DOM.span({className: "memberLabel " + member.type + "Label"},
member.name)
),

View File

@ -22,7 +22,6 @@ const CONTRACT_ID = "@mozilla.org/devtools/jsonview-sniffer;1";
const CLASS_ID = "{4148c488-dca1-49fc-a621-2a0097a62422}";
const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
const JSON_VIEW_TYPE = "JSON View";
const JSON_EXTENSION = "json";
const CONTENT_SNIFFER_CATEGORY = "net-content-sniffers";
/**
@ -64,10 +63,6 @@ var Sniffer = Class({
if (aRequest.contentType == JSON_TYPE) {
return JSON_VIEW_MIME_TYPE;
}
if (NetworkHelper.getFileExtension(aRequest.name) == JSON_EXTENSION) {
return JSON_VIEW_MIME_TYPE;
}
}
return "";

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -20,7 +20,6 @@
.memberLabelCell {
padding: 2px 0 2px 0px;
vertical-align: top;
}
.memberValueCell {
@ -31,7 +30,6 @@
.memberLabel {
cursor: default;
overflow: hidden;
padding-left: 18px;
white-space: nowrap;
}
@ -60,6 +58,11 @@
/******************************************************************************/
.memberRow.hasChildren > .memberLabelCell > .memberIcon:hover,
.memberRow.cropped > .memberLabelCell > .memberIcon:hover {
cursor: pointer;
}
.memberRow.hasChildren > .memberLabelCell > .memberLabel:hover,
.memberRow.cropped > .memberLabelCell > .memberLabel:hover {
cursor: pointer;
@ -71,6 +74,10 @@
background-color: #EFEFEF;
}
.memberRow {
padding: 3px 0 3px 0;
}
.panelNode-dom .memberRow td,
.panelNode-domSide .memberRow td {
border-bottom: 1px solid #EFEFEF;
@ -116,19 +123,38 @@
/******************************************************************************/
/* Twisties */
.memberRow.hasChildren > .memberLabelCell > .memberLabel,
.memberRow.cropped > .memberLabelCell > .memberLabel {
background-image: url(twisty-closed.svg);
background-repeat: no-repeat;
background-position: 2px calc(0.5em - 3px);
min-height: 12px;
.memberRow > .memberLabelCell > .memberIcon {
height: 14px;
width: 14px;
display: inline-block;
line-height: 15px;
vertical-align: bottom;
padding-right: 2px;
margin-left: 3px;
}
.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,
.memberRow.cropped.opened > .memberLabelCell > .memberLabel {
background-image: url(twisty-open.svg);
.memberRow.hasChildren > .memberLabelCell > .memberIcon,
.memberRow.cropped > .memberLabelCell > .memberIcon {
background-image: url("./twisty-closed.svg");
background-repeat: no-repeat;
min-height: 12px;
}
.memberRow.hasChildren.opened > .memberLabelCell > .memberIcon,
.memberRow.cropped.opened > .memberLabelCell > .memberIcon {
background-image: url("./twisty-open.svg");
background-repeat: no-repeat;
}
@media (min-resolution: 1.1dppx) {
.memberRow.hasChildren > .memberLabelCell > .memberIcon,
.memberRow.cropped > .memberLabelCell > .memberIcon {
background-image: url("./controls@2x.png");
}
.memberRow.hasChildren.opened > .memberLabelCell > .memberIcon,
.memberRow.cropped.opened > .memberLabelCell > .memberIcon {
background-image: url("./controls@2x.png");
}
}
/******************************************************************************/
@ -140,7 +166,6 @@
.memberLabelCell,
.memberValueCell {
display: table-cell;
}
.memberLabelCell {
@ -150,3 +175,42 @@
.memberRow:hover {
background-color: transparent !important;
}
/******************************************************************************/
/* Themes */
.theme-light .memberRow.hasChildren > .memberLabelCell > .memberIcon,
.theme-light .memberRow.cropped > .memberLabelCell > .memberIcon {
background-image: url("./controls.png");
background-size: 56px 28px;
background-repeat: no-repeat;
background-position: 0 -14px;
}
.theme-light .memberRow.hasChildren.opened > .memberLabelCell > .memberIcon,
.theme-light .memberRow.cropped.opened > .memberLabelCell > .memberIcon {
background-image: url("./controls.png");
background-size: 56px 28px;
background-repeat: no-repeat;
background-position: -14px -14px;
}
.theme-dark .memberRow.hasChildren > .memberLabelCell > .memberIcon,
.theme-dark .memberRow.cropped > .memberLabelCell > .memberIcon {
background-image: url("./controls.png");
background-size: 56px 28px;
background-repeat: no-repeat;
background-position: -28px -14px;
}
.theme-dark .memberRow.hasChildren.opened > .memberLabelCell > .memberIcon,
.theme-dark .memberRow.cropped.opened > .memberLabelCell > .memberIcon {
background-image: url("./controls.png");
background-size: 56px 28px;
background-repeat: no-repeat;
background-position: -42px -14px;
}
.theme-dark .memberRow:hover {
background-color: var(--theme-selection-background-semitransparent);
}

View File

@ -6,6 +6,8 @@
DevToolsModules(
'controls.png',
'controls@2x.png',
'dom-tree.css',
'general.css',
'headers-panel.css',

View File

@ -175,7 +175,7 @@
.theme-dark .domLabel,
.theme-light .domLabel {
color: var(--theme-highlight-bluegrey);
color: var(--theme-highlight-blue);
}
.theme-dark .objectBox-array .length,
@ -207,7 +207,7 @@
.theme-light .objectBox-object {
font-family: Lucida Grande, sans-serif;
font-weight: normal;
color: var(--theme-highlight-bluegrey);
color: var(--theme-highlight-blue);
white-space: pre-wrap;
}
@ -215,5 +215,5 @@
.theme-light .caption {
font-family: Lucida Grande, Tahoma, sans-serif;
font-weight: normal;
color: var(--theme-highlight-bluegrey);
color: var(--theme-highlight-blue);
}

View File

@ -20,10 +20,10 @@ Services.prefs.setBoolPref("devtools.memory.enabled", true);
var { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
var { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {});
var { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
var { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
var { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
var { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/main");
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
var { TargetFactory } = require("devtools/client/framework/target");
var { Toolbox } = require("devtools/client/framework/toolbox");

View File

@ -168,7 +168,7 @@ body {
.devtools-toolbar,
.devtools-sidebar-tabs tabs,
.devtools-sidebar-alltabs,
.CodeMirror-dialog { /* General toolbar styling */
.cm-s-mozilla .CodeMirror-dialog { /* General toolbar styling */
color: var(--theme-body-color-alt);
background-color: var(--theme-toolbar-background);
border-color: hsla(210,8%,5%,.6);

View File

@ -171,7 +171,7 @@ body {
.devtools-toolbar,
.devtools-sidebar-tabs tabs,
.devtools-sidebar-alltabs,
.CodeMirror-dialog { /* General toolbar styling */
.cm-s-mozilla .CodeMirror-dialog { /* General toolbar styling */
color: var(--theme-body-color-alt);
background-color: var(--theme-toolbar-background);
border-color: var(--theme-splitter-color);

27
devtools/install.rdf Normal file
View File

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<!--
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest"
em:id="devtools@mozilla.org"
em:name="Developer Tools (local version)"
em:description="Add-on to load DevTools from local sources and easily reload them with Ctrl+Alt+r shortcut"
em:version="44.0a1"
em:type="2"
em:creator="Mozilla">
<em:bootstrap>true</em:bootstrap>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>44.0a1</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -803,36 +803,6 @@ var NetworkHelper = {
let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
aStore.set(aUrl, uri);
return uri;
},
/**
* Returns extension for file URLs (e.g. 'json').
* Not everyURL has an extension and this method works as follows:
* 1) Remove query string
* 2) Get part after the last slash (a file name)
* 3) Look for the last dot (an extension)
*/
getFileExtension: function(aUrl) {
if (!aUrl) {
return;
}
// Remove query string from the URL if any.
let queryString = aUrl.indexOf("?");
if (queryString != -1) {
aUrl = aUrl.substr(0, queryString);
}
// Look for the part after last slash
var lastSlash = aUrl.lastIndexOf("/");
var fileName = aUrl.substr(lastSlash + 1);
if (!fileName) {
return;
}
// Now get the file extension.
var lastDot = fileName.lastIndexOf(".");
return fileName.substr(lastDot + 1);
}
};

View File

@ -4415,25 +4415,26 @@ ContentParent::HasNotificationPermission(const IPC::Principal& aPrincipal)
}
bool
ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
const nsString& aText, const bool& aTextClickable,
const nsString& aCookie, const nsString& aName,
const nsString& aBidi, const nsString& aLang,
const nsString& aData,
const IPC::Principal& aPrincipal,
const bool& aInPrivateBrowsing)
ContentParent::RecvShowAlert(const AlertNotificationType& aAlert)
{
if (!HasNotificationPermission(aPrincipal)) {
nsCOMPtr<nsIAlertNotification> alert(dont_AddRef(aAlert));
if (NS_WARN_IF(!alert)) {
return true;
}
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = alert->GetPrincipal(getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv)) ||
!HasNotificationPermission(IPC::Principal(principal))) {
return true;
}
nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID));
if (sysAlerts) {
sysAlerts->ShowAlertNotification(aImageUrl, aTitle, aText, aTextClickable,
aCookie, this, aName, aBidi, aLang,
aData, aPrincipal, aInPrivateBrowsing);
}
return true;
sysAlerts->ShowAlert(alert, this);
}
return true;
}
bool

View File

@ -901,14 +901,7 @@ private:
bool HasNotificationPermission(const IPC::Principal& aPrincipal);
virtual bool
RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
const nsString& aText, const bool& aTextClickable,
const nsString& aCookie, const nsString& aName,
const nsString& aBidi, const nsString& aLang,
const nsString& aData,
const IPC::Principal& aPrincipal,
const bool& aInPrivateBrowsing) override;
virtual bool RecvShowAlert(const AlertNotificationType& aAlert) override;
virtual bool RecvCloseAlert(const nsString& aName,
const IPC::Principal& aPrincipal) override;

View File

@ -74,6 +74,7 @@ include ProfilerTypes;
include "mozilla/dom/PContentBridgeParent.h";
using GeoPosition from "nsGeoPositionIPCSerialiser.h";
using AlertNotificationType from "mozilla/AlertNotificationIPCSerializer.h";
using struct ChromePackage from "mozilla/chrome/RegistryMessageUtils.h";
using struct SubstitutionMapping from "mozilla/chrome/RegistryMessageUtils.h";
@ -881,17 +882,7 @@ parent:
CpowEntry[] aCpows, Principal aPrincipal)
returns (StructuredCloneData[] retval);
ShowAlertNotification(nsString imageUrl,
nsString title,
nsString text,
bool textClickable,
nsString cookie,
nsString name,
nsString bidi,
nsString lang,
nsString data,
Principal principal,
bool inPrivateBrowsing);
ShowAlert(AlertNotificationType alert);
CloseAlert(nsString name, Principal principal);

View File

@ -7,6 +7,7 @@
#include "mozilla/dom/DesktopNotificationBinding.h"
#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
#include "mozilla/dom/ToJSValue.h"
#include "nsComponentManagerUtils.h"
#include "nsContentPermissionHelper.h"
#include "nsXULAppAPI.h"
#include "mozilla/dom/PBrowserChild.h"
@ -114,16 +115,20 @@ DesktopNotification::PostDesktopNotification()
nsIPrincipal* principal = doc->NodePrincipal();
nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
bool inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
return alerts->ShowAlertNotification(mIconURL, mTitle, mDescription,
true,
uniqueName,
mObserver,
uniqueName,
NS_LITERAL_STRING("auto"),
EmptyString(),
EmptyString(),
principal,
inPrivateBrowsing);
nsCOMPtr<nsIAlertNotification> alert =
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
nsresult rv = alert->Init(uniqueName, mIconURL, mTitle,
mDescription,
true,
uniqueName,
NS_LITERAL_STRING("auto"),
EmptyString(),
EmptyString(),
principal,
inPrivateBrowsing);
NS_ENSURE_SUCCESS(rv, rv);
return alerts->ShowAlert(alert, mObserver);
}
DesktopNotification::DesktopNotification(const nsAString & title,

View File

@ -23,6 +23,7 @@
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
#include "nsAlertsUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsContentPermissionHelper.h"
#include "nsContentUtils.h"
#include "nsCRTGlue.h"
@ -1787,11 +1788,19 @@ Notification::ShowInternal()
nsAutoString alertName;
GetAlertName(alertName);
alertService->ShowAlertNotification(iconUrl, mTitle, mBody, true,
uniqueCookie, alertObserver, alertName,
DirectionToString(mDir), mLang,
mDataAsBase64, GetPrincipal(),
inPrivateBrowsing);
nsCOMPtr<nsIAlertNotification> alert =
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
NS_ENSURE_TRUE_VOID(alert);
rv = alert->Init(alertName, iconUrl, mTitle, mBody,
true,
uniqueCookie,
DirectionToString(mDir),
mLang,
mDataAsBase64,
GetPrincipal(),
inPrivateBrowsing);
NS_ENSURE_SUCCESS_VOID(rv);
alertService->ShowAlert(alert, alertObserver);
}
/* static */ bool

View File

@ -98,15 +98,15 @@ function testNonDefaultContentToolbars(toolbars) {
function testNonDefaultChromeToolbars(toolbars) {
// None of the toolbars should be visible if hidden with chrome privileges
ok(!toolbars.locationbar,
"locationbar should be visible on default window.open()");
"locationbar should not be visible with location=no");
ok(!toolbars.menubar,
"menubar be visible on default window.open()");
"menubar should not be visible with menubar=no");
ok(!toolbars.personalbar,
"personalbar should be visible on default window.open()");
"personalbar should not be visible with personalbar=no");
ok(!toolbars.statusbar,
"statusbar should be visible on default window.open()");
"statusbar should not be visible with status=no");
ok(!toolbars.toolbar,
"toolbar should be visible on default window.open()");
"toolbar should not be visible with toolbar=no");
}
/**
@ -147,7 +147,42 @@ add_task(function*() {
let popupToolbars = yield getToolbarsFromBrowserContent(popupBrowser);
testNonDefaultContentToolbars(popupToolbars);
// Cleanup
// Ensure that chrome toolbars agree with content
let chromeToolbars = getToolbarsFromWindowChrome(popupWindow);
testNonDefaultContentToolbars(chromeToolbars);
// Close the new window
yield BrowserTestUtils.closeWindow(popupWindow);
});
});
/**
* Ensure that toolbars of a window opened to about:blank in the content context
* have the correct visibility.
*
* A window opened with "location=no, personalbar=no, toolbar=no, scrollbars=no,
* menubar=no, status=no", should only have location visible.
*/
add_task(function*() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: CONTENT_PAGE,
}, function*(browser) {
// Open a blank window with toolbars hidden
let winPromise = BrowserTestUtils.waitForNewWindow();
yield BrowserTestUtils.synthesizeMouseAtCenter("#winOpenNoURLNonDefault", {}, browser);
let popupWindow = yield winPromise;
// No need to wait for this window to load, since it's loading about:blank
let popupBrowser = popupWindow.gBrowser.selectedBrowser;
let popupToolbars = yield getToolbarsFromBrowserContent(popupBrowser);
testNonDefaultContentToolbars(popupToolbars);
// Ensure that chrome toolbars agree with content
let chromeToolbars = getToolbarsFromWindowChrome(popupWindow);
testNonDefaultContentToolbars(chromeToolbars);
// Close the new window
yield BrowserTestUtils.closeWindow(popupWindow);
});
});

View File

@ -7,6 +7,7 @@
<p><a id="winOpenDefault" href="#" onclick="return openWindow();">Open a new window via window.open with default features.</a></p>
<p><a id="winOpenNonDefault" href="#" onclick="return openWindow('resizable=no, location=no, personalbar=no, toolbar=no, scrollbars=no, menubar=no, status=no, directories=no, height=100, width=500');">Open a new window via window.open with non-default features.</a></p>
<p><a id="winOpenDialog" href="#" onclick="return openWindow('dialog=yes');">Open a new window via window.open with dialog=1.</a></p>
<p><a id="winOpenNoURLNonDefault" href="#" onclick="return openBlankWindow('location=no, toolbar=no, height=100, width=100');">Open a blank new window via window.open with non-default features.</a></p>
<p><a id="targetBlank" href="about:robots" target="_blank">Open a new window via target="_blank".</a></p>
</body>
</html>
@ -16,4 +17,9 @@ function openWindow(aFeatures="") {
window.open("about:robots", "_blank", aFeatures);
return false;
}
function openBlankWindow(aFeatures="") {
window.open("", "_blank", aFeatures);
return false;
}
</script>

View File

@ -29,26 +29,34 @@ var MockServices = (function () {
});
var mockAlertsService = {
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name) {
showAlert: function(alert, alertListener) {
var listener = SpecialPowers.wrap(alertListener);
activeAlertNotifications[name] = {
activeAlertNotifications[alert.name] = {
listener: listener,
cookie: cookie,
title: title
cookie: alert.cookie,
title: alert.title
};
// fake async alert show event
if (listener) {
setTimeout(function () {
listener.observe(null, "alertshow", cookie);
listener.observe(null, "alertshow", alert.cookie);
}, 100);
setTimeout(function () {
listener.observe(null, "alertclickcallback", cookie);
listener.observe(null, "alertclickcallback", alert.cookie);
}, 100);
}
},
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name) {
this.showAlert({
name: name,
cookie: cookie,
title: title
}, alertListener);
},
showAppNotification: function(aImageUrl, aTitle, aText, aAlertListener, aDetails) {
var listener = aAlertListener || (activeAlertNotifications[aDetails.id] ? activeAlertNotifications[aDetails.id].listener : undefined);
activeAppNotifications[aDetails.id] = {

View File

@ -8,17 +8,23 @@ var registrar = SpecialPowers.wrap(SpecialPowers.Components).manager.
QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar);
var mockAlertsService = {
showAlert: function(alert, alertListener) {
// probably should do this async....
SpecialPowers.wrap(alertListener).observe(null, "alertshow", alert.cookie);
if (SpecialPowers.getBoolPref("notification.prompt.testing.click_on_notification") == true) {
SpecialPowers.wrap(alertListener).observe(null, "alertclickcallback", alert.cookie);
}
SpecialPowers.wrap(alertListener).observe(null, "alertfinished", alert.cookie);
},
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name, bidi,
lang, data) {
// probably should do this async....
SpecialPowers.wrap(alertListener).observe(null, "alertshow", cookie);
if (SpecialPowers.getBoolPref("notification.prompt.testing.click_on_notification") == true) {
SpecialPowers.wrap(alertListener).observe(null, "alertclickcallback", cookie);
}
SpecialPowers.wrap(alertListener).observe(null, "alertfinished", cookie);
return this.showAlert({
cookie: cookie
}, alertListener);
},
showAppNotification: function(imageUrl, title, text, alertListener, details) {

View File

@ -23,15 +23,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=782211
const ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/alerts-service;1";
var mockAlertsService = {
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name, dir,
lang, data) {
notificationsCreated.push(name);
showAlert: function(alert, alertListener) {
notificationsCreated.push(alert.name);
if (notificationsCreated.length == 3) {
checkNotifications();
}
},
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name, dir,
lang, data) {
this.showAlert({ name: name });
},
QueryInterface: function(aIID) {
if (SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService)) {

View File

@ -23,13 +23,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=874090
const ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/alerts-service;1";
var mockAlertsService = {
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name, dir, lang, data) {
ok(true, "System principal was granted permission and is able to call showAlertNotification.");
showAlert: function(alert, alertListener) {
ok(true, "System principal was granted permission and is able to call showAlert.");
unregisterMock();
SimpleTest.finish();
},
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name, dir, lang, data) {
this.showAlert();
},
QueryInterface: function(aIID) {
if (aIID.equals(Components.interfaces.nsISupports) ||
aIID.equals(Components.interfaces.nsIAlertsService)) {

View File

@ -117,6 +117,9 @@ var AlertsService = {
"", ALERTS_SERVICE_CONTRACT_ID, null);
},
showAlert: function() {
},
showAlertNotification: function() {
},
};

View File

@ -2170,13 +2170,21 @@ public class BrowserApp extends GeckoApp
final Tab tab = Tabs.getInstance().getSelectedTab();
if (tab != null) {
final String userRequested = tab.getUserRequested();
final String userSearchTerm = tab.getUserRequested();
// Check to see if there's a user-entered search term,
// which we save whenever the user performs a search.
url = (TextUtils.isEmpty(userRequested) ? tab.getURL() : userRequested);
}
final String telemetryMsg;
if (!TextUtils.isEmpty(userSearchTerm)) {
url = userSearchTerm;
telemetryMsg = "urlbar-userentered";
} else {
url = tab.getURL();
telemetryMsg = url.isEmpty() ? "urlbar-empty" : "urlbar-url";
}
Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.ACTIONBAR, telemetryMsg);
}
enterEditingMode(url);
}
@ -2210,7 +2218,12 @@ public class BrowserApp extends GeckoApp
mBrowserToolbar.startEditing(url, animator);
showHomePagerWithAnimator(panelId, animator);
final boolean isUserSearchTerm = !TextUtils.isEmpty(selectedTab.getUserRequested());
if (isUserSearchTerm && AppConstants.NIGHTLY_BUILD) {
showBrowserSearchAfterAnimation(animator);
} else {
showHomePagerWithAnimator(panelId, animator);
}
animator.start();
Telemetry.startUISession(TelemetryContract.Session.AWESOMESCREEN);
@ -2622,6 +2635,24 @@ public class BrowserApp extends GeckoApp
refreshToolbarHeight();
}
private void showBrowserSearchAfterAnimation(PropertyAnimator animator) {
if (animator == null) {
showBrowserSearch();
return;
}
animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
@Override
public void onPropertyAnimationStart() {
}
@Override
public void onPropertyAnimationEnd() {
showBrowserSearch();
}
});
}
private void showBrowserSearch() {
if (mBrowserSearch.getUserVisibleHint()) {
return;
@ -2672,7 +2703,7 @@ public class BrowserApp extends GeckoApp
// To prevent overdraw, the HomePager is hidden when BrowserSearch is displayed:
// reverse that.
mHomePagerContainer.setVisibility(View.VISIBLE);
showHomePager(Tabs.getInstance().getSelectedTab().getMostRecentHomePanel());
mBrowserSearchContainer.setVisibility(View.INVISIBLE);

View File

@ -87,6 +87,11 @@ public class DownloadAction extends BaseAction {
temporaryFile = createTemporaryFile(context, content);
if (!canWrite(temporaryFile, destinationFile)) {
throw new RecoverableDownloadContentException(RecoverableDownloadContentException.DISK_IO,
"Temporary or destination file not writeable");
}
if (!hasEnoughDiskSpace(content, destinationFile, temporaryFile)) {
Log.d(LOGTAG, "Not enough disk space to save content. Skipping download.");
continue;
@ -125,7 +130,7 @@ public class DownloadAction extends BaseAction {
temporaryFile.delete();
}
} catch (RecoverableDownloadContentException e) {
Log.w(LOGTAG, "Downloading content failed (Recoverable): " + content , e);
Log.w(LOGTAG, "Downloading content failed (Recoverable): " + content, e);
if (e.shouldBeCountedAsFailure()) {
catalog.rememberFailure(content, e.getErrorType());
@ -336,4 +341,14 @@ public class DownloadAction extends BaseAction {
return true;
}
protected boolean canWrite(File... files) {
for (File file : files) {
if (!file.canWrite()) {
return false;
}
}
return true;
}
}

View File

@ -168,6 +168,7 @@ public class TestDownloadAction {
doReturn(file).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
doReturn(false).when(action).verify(eq(file), anyString());
doNothing().when(action).download(any(HttpClient.class), anyString(), eq(file));
doReturn(true).when(action).verify(eq(file), anyString());
@ -202,6 +203,7 @@ public class TestDownloadAction {
DownloadAction action = spy(new DownloadAction(null));
doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
File temporaryFile = mockFileWithSize(1337L);
doReturn(temporaryFile).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
@ -301,6 +303,7 @@ public class TestDownloadAction {
File destinationFile = mockNotExistingFile();
doReturn(destinationFile).when(action).getDestinationFile(RuntimeEnvironment.application, content);
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
doReturn(true).when(action).verify(eq(temporaryFile), anyString());
doNothing().when(action).extract(eq(temporaryFile), eq(destinationFile), anyString());
@ -333,6 +336,7 @@ public class TestDownloadAction {
DownloadAction action = spy(new DownloadAction(null));
doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
doNothing().when(action).download(any(HttpClient.class), anyString(), any(File.class));
doReturn(false).when(action).verify(any(File.class), anyString());
@ -443,6 +447,7 @@ public class TestDownloadAction {
doReturn(mockNotExistingFile()).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
doReturn(mockNotExistingFile()).when(action).getDestinationFile(RuntimeEnvironment.application, content);
doReturn(true).when(action).hasEnoughDiskSpace(eq(content), any(File.class), any(File.class));
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
HttpClient client = mock(HttpClient.class);
doThrow(IOException.class).when(client).execute(any(HttpUriRequest.class));
@ -499,6 +504,32 @@ public class TestDownloadAction {
verify(catalog, times(11)).rememberFailure(eq(content), anyInt());
}
/**
* Scenario: Temporary or destination file is not writable.
*
* Verify that:
* * No download is performed
* * Error is counted as failure
*/
@Test
public void testNoDownIsPerformedIfFilesAreNotWritable() throws Exception{
DownloadContent content = createFont();
DownloadContentCatalog catalog = mockCatalogWithScheduledDownloads(content);
DownloadAction action = spy(new DownloadAction(null));
doReturn(true).when(action).isConnectedToNetwork(RuntimeEnvironment.application);
doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
doReturn(mockNotExistingFile()).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
doReturn(mockNotExistingFile()).when(action).getDestinationFile(RuntimeEnvironment.application, content);
doReturn(false).when(action).canWrite(any(File.class), any(File.class));
action.perform(RuntimeEnvironment.application, catalog);
verify(action).canWrite(any(File.class), any(File.class));
verify(action, never()).download(any(HttpClient.class), anyString(), any(File.class));
verify(catalog).rememberFailure(eq(content), anyInt());
}
private DownloadContent createFont() {
return createFontWithSize(102400L);
}

View File

@ -159,7 +159,7 @@ public class AppMenuComponent extends BaseComponent {
* This method is dependent on not having two views with equivalent contentDescription / text.
*/
private View findAppMenuItemView(String text) {
mSolo.waitForText(text, 1, MAX_WAITTIME_FOR_MENU_UPDATE_IN_MS);
mSolo.waitForText(String.format("^%s$", text), 1, MAX_WAITTIME_FOR_MENU_UPDATE_IN_MS);
final List<View> views = mSolo.getViews();
@ -298,7 +298,8 @@ public class AppMenuComponent extends BaseComponent {
private boolean isLegacyMoreMenuOpen() {
// Check if the first menu option is visible.
return mSolo.searchText(mSolo.getString(R.string.share), true);
final String shareTitle = mSolo.getString(R.string.share);
return mSolo.searchText(String.format("^%s$", shareTitle), true);
}
/**
@ -310,7 +311,7 @@ public class AppMenuComponent extends BaseComponent {
*/
private boolean isMenuOpen(String menuItemTitle) {
final View menuItemView = findAppMenuItemView(menuItemTitle);
return isMenuOpen(menuItemView) ? true : mSolo.searchText(menuItemTitle, true);
return isMenuOpen(menuItemView) ? true : mSolo.searchText(String.format("^%s$", menuItemTitle), true);
}
/**

View File

@ -0,0 +1,125 @@
/* This Source Code Form is subject to the terms of the Mozilla Pub
* License, v. 2.0. If a copy of the MPL was not distributed with t
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/AlertNotification.h"
namespace mozilla {
NS_IMPL_CYCLE_COLLECTION(AlertNotification, mPrincipal)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AlertNotification)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAlertNotification)
NS_INTERFACE_MAP_ENTRY(nsIAlertNotification)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(AlertNotification)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AlertNotification)
AlertNotification::AlertNotification()
: mTextClickable(false)
, mPrincipal(nullptr)
, mInPrivateBrowsing(false)
{}
AlertNotification::~AlertNotification()
{}
NS_IMETHODIMP
AlertNotification::Init(const nsAString& aName, const nsAString& aImageURL,
const nsAString& aTitle, const nsAString& aText,
bool aTextClickable, const nsAString& aCookie,
const nsAString& aDir, const nsAString& aLang,
const nsAString& aData, nsIPrincipal* aPrincipal,
bool aInPrivateBrowsing)
{
mName = aName;
mImageURL = aImageURL;
mTitle = aTitle;
mText = aText;
mTextClickable = aTextClickable;
mCookie = aCookie;
mDir = aDir;
mLang = aLang;
mData = aData;
mPrincipal = aPrincipal;
mInPrivateBrowsing = aInPrivateBrowsing;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetName(nsAString& aName)
{
aName = mName;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetImageURL(nsAString& aImageURL)
{
aImageURL = mImageURL;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetTitle(nsAString& aTitle)
{
aTitle = mTitle;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetText(nsAString& aText)
{
aText = mText;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetTextClickable(bool* aTextClickable)
{
*aTextClickable = mTextClickable;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetCookie(nsAString& aCookie)
{
aCookie = mCookie;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetDir(nsAString& aDir)
{
aDir = mDir;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetLang(nsAString& aLang)
{
aLang = mLang;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetData(nsAString& aData)
{
aData = mData;
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetPrincipal(nsIPrincipal** aPrincipal)
{
NS_IF_ADDREF(*aPrincipal = mPrincipal);
return NS_OK;
}
NS_IMETHODIMP
AlertNotification::GetInPrivateBrowsing(bool* aInPrivateBrowsing)
{
*aInPrivateBrowsing = mInPrivateBrowsing;
return NS_OK;
}
} // namespace mozilla

View File

@ -0,0 +1,44 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_AlertNotification_h__
#define mozilla_AlertNotification_h__
#include "nsIAlertsService.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIPrincipal.h"
#include "nsString.h"
namespace mozilla {
class AlertNotification final : public nsIAlertNotification
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(AlertNotification,
nsIAlertNotification)
NS_DECL_NSIALERTNOTIFICATION
AlertNotification();
protected:
virtual ~AlertNotification();
private:
nsString mName;
nsString mImageURL;
nsString mTitle;
nsString mText;
bool mTextClickable;
nsString mCookie;
nsString mDir;
nsString mLang;
nsString mData;
nsCOMPtr<nsIPrincipal> mPrincipal;
bool mInPrivateBrowsing;
};
} // namespace mozilla
#endif /* mozilla_AlertNotification_h__ */

View File

@ -0,0 +1,119 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_AlertNotificationIPCSerializer_h__
#define mozilla_AlertNotificationIPCSerializer_h__
#include "nsComponentManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsIAlertsService.h"
#include "nsIPrincipal.h"
#include "nsString.h"
#include "ipc/IPCMessageUtils.h"
#include "mozilla/dom/PermissionMessageUtils.h"
typedef nsIAlertNotification* AlertNotificationType;
namespace IPC {
template <>
struct ParamTraits<AlertNotificationType>
{
typedef AlertNotificationType paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
bool isNull = !aParam;
if (isNull) {
WriteParam(aMsg, isNull);
return;
}
nsString name, imageURL, title, text, cookie, dir, lang, data;
bool textClickable, inPrivateBrowsing;
nsCOMPtr<nsIPrincipal> principal;
if (NS_WARN_IF(NS_FAILED(aParam->GetName(name))) ||
NS_WARN_IF(NS_FAILED(aParam->GetImageURL(imageURL))) ||
NS_WARN_IF(NS_FAILED(aParam->GetTitle(title))) ||
NS_WARN_IF(NS_FAILED(aParam->GetText(text))) ||
NS_WARN_IF(NS_FAILED(aParam->GetTextClickable(&textClickable))) ||
NS_WARN_IF(NS_FAILED(aParam->GetCookie(cookie))) ||
NS_WARN_IF(NS_FAILED(aParam->GetDir(dir))) ||
NS_WARN_IF(NS_FAILED(aParam->GetLang(lang))) ||
NS_WARN_IF(NS_FAILED(aParam->GetData(data))) ||
NS_WARN_IF(NS_FAILED(aParam->GetPrincipal(getter_AddRefs(principal)))) ||
NS_WARN_IF(NS_FAILED(aParam->GetInPrivateBrowsing(&inPrivateBrowsing)))) {
// Write a `null` object if any getter returns an error. Otherwise, the
// receiver will try to deserialize an incomplete object and crash.
WriteParam(aMsg, /* isNull */ true);
return;
}
WriteParam(aMsg, isNull);
WriteParam(aMsg, name);
WriteParam(aMsg, imageURL);
WriteParam(aMsg, title);
WriteParam(aMsg, text);
WriteParam(aMsg, textClickable);
WriteParam(aMsg, cookie);
WriteParam(aMsg, dir);
WriteParam(aMsg, lang);
WriteParam(aMsg, data);
WriteParam(aMsg, IPC::Principal(principal));
WriteParam(aMsg, inPrivateBrowsing);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
bool isNull;
NS_ENSURE_TRUE(ReadParam(aMsg, aIter, &isNull), false);
if (isNull) {
*aResult = nullptr;
return true;
}
nsString name, imageURL, title, text, cookie, dir, lang, data;
bool textClickable, inPrivateBrowsing;
IPC::Principal principal;
if (!ReadParam(aMsg, aIter, &name) ||
!ReadParam(aMsg, aIter, &imageURL) ||
!ReadParam(aMsg, aIter, &title) ||
!ReadParam(aMsg, aIter, &text) ||
!ReadParam(aMsg, aIter, &textClickable) ||
!ReadParam(aMsg, aIter, &cookie) ||
!ReadParam(aMsg, aIter, &dir) ||
!ReadParam(aMsg, aIter, &lang) ||
!ReadParam(aMsg, aIter, &data) ||
!ReadParam(aMsg, aIter, &principal) ||
!ReadParam(aMsg, aIter, &inPrivateBrowsing)) {
return false;
}
nsCOMPtr<nsIAlertNotification> alert =
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
if (NS_WARN_IF(!alert)) {
*aResult = nullptr;
return true;
}
nsresult rv = alert->Init(name, imageURL, title, text, textClickable,
cookie, dir, lang, data, principal,
inPrivateBrowsing);
if (NS_WARN_IF(NS_FAILED(rv))) {
*aResult = nullptr;
return true;
}
alert.forget(aResult);
return true;
}
};
} // namespace IPC
#endif /* mozilla_AlertNotificationIPCSerializer_h__ */

View File

@ -16,7 +16,13 @@ EXPORTS += [
'nsAlertsUtils.h',
]
EXPORTS.mozilla += [
'AlertNotification.h',
'AlertNotificationIPCSerializer.h',
]
UNIFIED_SOURCES += [
'AlertNotification.cpp',
'nsAlertsService.cpp',
'nsAlertsUtils.cpp',
'nsXULAlerts.cpp',

View File

@ -73,40 +73,66 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
nsIPrincipal * aPrincipal,
bool aInPrivateBrowsing)
{
nsCOMPtr<nsIAlertNotification> alert =
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
aAlertText, aAlertTextClickable,
aAlertCookie, aBidi, aLang, aData,
aPrincipal, aInPrivateBrowsing);
NS_ENSURE_SUCCESS(rv, rv);
return ShowAlert(alert, aAlertListener);
}
NS_IMETHODIMP nsAlertsService::ShowAlert(nsIAlertNotification * aAlert,
nsIObserver * aAlertListener)
{
NS_ENSURE_ARG(aAlert);
nsAutoString cookie;
nsresult rv = aAlert->GetCookie(cookie);
NS_ENSURE_SUCCESS(rv, rv);
if (XRE_IsContentProcess()) {
ContentChild* cpc = ContentChild::GetSingleton();
if (aAlertListener)
cpc->AddRemoteAlertObserver(PromiseFlatString(aAlertCookie), aAlertListener);
cpc->AddRemoteAlertObserver(cookie, aAlertListener);
cpc->SendShowAlertNotification(PromiseFlatString(aImageUrl),
PromiseFlatString(aAlertTitle),
PromiseFlatString(aAlertText),
aAlertTextClickable,
PromiseFlatString(aAlertCookie),
PromiseFlatString(aAlertName),
PromiseFlatString(aBidi),
PromiseFlatString(aLang),
PromiseFlatString(aData),
IPC::Principal(aPrincipal),
aInPrivateBrowsing);
cpc->SendShowAlert(aAlert);
return NS_OK;
}
nsAutoString imageUrl;
rv = aAlert->GetImageURL(imageUrl);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString title;
rv = aAlert->GetTitle(title);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString text;
rv = aAlert->GetText(text);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString name;
rv = aAlert->GetName(name);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> principal;
rv = aAlert->GetPrincipal(getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);
#ifdef MOZ_WIDGET_ANDROID
mozilla::AndroidBridge::Bridge()->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertCookie,
aAlertListener, aAlertName, aPrincipal);
mozilla::AndroidBridge::Bridge()->ShowAlertNotification(imageUrl, title, text, cookie,
aAlertListener, name, principal);
return NS_OK;
#else
// Check if there is an optional service that handles system-level notifications
nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID));
nsresult rv;
if (sysAlerts) {
rv = sysAlerts->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
aAlertCookie, aAlertListener, aAlertName,
aBidi, aLang, aData,
IPC::Principal(aPrincipal),
aInPrivateBrowsing);
rv = sysAlerts->ShowAlert(aAlert, aAlertListener);
if (NS_SUCCEEDED(rv))
return NS_OK;
}
@ -114,14 +140,30 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
if (!ShouldShowAlert()) {
// Do not display the alert. Instead call alertfinished and get out.
if (aAlertListener)
aAlertListener->Observe(nullptr, "alertfinished", PromiseFlatString(aAlertCookie).get());
aAlertListener->Observe(nullptr, "alertfinished", cookie.get());
return NS_OK;
}
bool textClickable;
rv = aAlert->GetTextClickable(&textClickable);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString bidi;
rv = aAlert->GetDir(bidi);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString lang;
rv = aAlert->GetLang(lang);
NS_ENSURE_SUCCESS(rv, rv);
bool inPrivateBrowsing;
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
NS_ENSURE_SUCCESS(rv, rv);
// Use XUL notifications as a fallback if above methods have failed.
rv = mXULAlerts.ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
aAlertCookie, aAlertListener, aAlertName,
aBidi, aLang, aPrincipal, aInPrivateBrowsing);
rv = mXULAlerts.ShowAlertNotification(imageUrl, title, text, textClickable,
cookie, aAlertListener, name,
bidi, lang, principal, inPrivateBrowsing);
return rv;
#endif // !MOZ_WIDGET_ANDROID
}

View File

@ -8,9 +8,96 @@
interface nsIPrincipal;
[scriptable, uuid(9d0284bf-db40-42da-8f0d-c2769dbde7aa)]
%{C++
#define ALERT_NOTIFICATION_CONTRACTID "@mozilla.org/alert-notification;1"
%}
[scriptable, uuid(b26b4a67-81b0-4270-8311-1e00a097ef92)]
interface nsIAlertNotification : nsISupports
{
/** Initializes an alert notification. */
void init([optional] in AString name,
[optional] in AString imageURL,
[optional] in AString title,
[optional] in AString text,
[optional] in boolean textClickable,
[optional] in AString cookie,
[optional] in AString dir,
[optional] in AString lang,
[optional] in AString data,
[optional] in nsIPrincipal principal,
[optional] in boolean inPrivateBrowsing);
/**
* The name of the notification. This is currently only used on Android and
* OS X. On Android, the name is hashed and used as a notification ID.
* Notifications will replace previous notifications with the same name.
*/
readonly attribute AString name;
/**
* A URL identifying the image to put in the alert. The OS X backend limits
* the amount of time it will wait for the image to load to six seconds. After
* that time, the alert will show without an image.
*/
readonly attribute AString imageURL;
/** The title for the alert. */
readonly attribute AString title;
/** The contents of the alert. */
readonly attribute AString text;
/**
* Controls the click behavior. If true, the alert listener will be notified
* when the user clicks on the alert.
*/
readonly attribute boolean textClickable;
/**
* An opaque cookie that will be passed to the alert listener for each
* callback.
*/
readonly attribute AString cookie;
/**
* Bidi override for the title and contents. Valid values are "auto", "ltr",
* or "rtl". Ignored if the backend doesn't support localization.
*/
readonly attribute AString dir;
/**
* Language of the title and text. Ignored if the backend doesn't support
* localization.
*/
readonly attribute AString lang;
/**
* A Base64-encoded structured clone buffer containing data associated with
* this alert. Only used for web notifications. Chrome callers should use a
* cookie instead.
*/
readonly attribute AString data;
/**
* The principal of the page that created the alert. Used for IPC security
* checks, and to determine whether the alert should show the source string
* and action buttons.
*/
readonly attribute nsIPrincipal principal;
/**
* Controls the image loading behavior. If true, the image URL will be loaded
* in private browsing mode.
*/
readonly attribute boolean inPrivateBrowsing;
};
[scriptable, uuid(f7a36392-d98b-4141-a7d7-4e46642684e3)]
interface nsIAlertsService : nsISupports
{
void showAlert(in nsIAlertNotification alert,
[optional] in nsIObserver alertListener);
/**
* Displays a sliding notification window.
*

View File

@ -97,6 +97,9 @@
/////////////////////////////////////////////////////////////////////////////
#define ALERT_NOTIFICATION_CID \
{ 0x9a7b7a41, 0x0b47, 0x47f7, { 0xb6, 0x1b, 0x15, 0xa2, 0x10, 0xd6, 0xf0, 0x20 } }
// {A0CCAAF8-09DA-44D8-B250-9AC3E93C8117}
#define NS_ALERTSSERVICE_CID \
{ 0xa0ccaaf8, 0x9da, 0x44d8, { 0xb2, 0x50, 0x9a, 0xc3, 0xe9, 0x3c, 0x81, 0x17 } }

View File

@ -16,6 +16,7 @@
#include "nsParentalControlsService.h"
#endif
#include "mozilla/AlertNotification.h"
#include "nsAlertsService.h"
#include "nsDownloadManager.h"
@ -82,6 +83,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsFindService)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsParentalControlsService)
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR(AlertNotification)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAlertsService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsDownloadManager,
@ -138,6 +140,7 @@ NS_DEFINE_NAMED_CID(NS_TOOLKIT_PERFORMANCESTATSSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_TOOLKIT_TERMINATOR_CID);
#endif
NS_DEFINE_NAMED_CID(NS_USERINFO_CID);
NS_DEFINE_NAMED_CID(ALERT_NOTIFICATION_CID);
NS_DEFINE_NAMED_CID(NS_ALERTSSERVICE_CID);
#if !defined(MOZ_DISABLE_PARENTAL_CONTROLS)
NS_DEFINE_NAMED_CID(NS_PARENTALCONTROLSSERVICE_CID);
@ -173,6 +176,7 @@ static const Module::CIDEntry kToolkitCIDs[] = {
{ &kNS_TOOLKIT_PERFORMANCESTATSSERVICE_CID, false, nullptr, nsPerformanceStatsServiceConstructor },
#endif // defined (MOZ_HAS_PERFSTATS)
{ &kNS_USERINFO_CID, false, nullptr, nsUserInfoConstructor },
{ &kALERT_NOTIFICATION_CID, false, nullptr, AlertNotificationConstructor },
{ &kNS_ALERTSSERVICE_CID, false, nullptr, nsAlertsServiceConstructor },
#if !defined(MOZ_DISABLE_PARENTAL_CONTROLS)
{ &kNS_PARENTALCONTROLSSERVICE_CID, false, nullptr, nsParentalControlsServiceConstructor },
@ -210,6 +214,7 @@ static const Module::ContractIDEntry kToolkitContracts[] = {
{ NS_TOOLKIT_PERFORMANCESTATSSERVICE_CONTRACTID, &kNS_TOOLKIT_PERFORMANCESTATSSERVICE_CID },
#endif // defined (MOZ_HAS_PERFSTATS)
{ NS_USERINFO_CONTRACTID, &kNS_USERINFO_CID },
{ ALERT_NOTIFICATION_CONTRACTID, &kALERT_NOTIFICATION_CID },
{ NS_ALERTSERVICE_CONTRACTID, &kNS_ALERTSSERVICE_CID },
#if !defined(MOZ_DISABLE_PARENTAL_CONTROLS)
{ NS_PARENTALCONTROLSSERVICE_CONTRACTID, &kNS_PARENTALCONTROLSSERVICE_CID },

View File

@ -9,6 +9,7 @@
#include "imgIRequest.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsIAlertsService.h"
#include "nsIImageToPixbuf.h"
#include "nsIStringBundle.h"
#include "nsIObserverService.h"
@ -186,6 +187,11 @@ nsAlertsIconListener::ShowAlert(GdkPixbuf* aPixbuf)
if (!mNotification)
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsIObserverService> obsServ =
do_GetService("@mozilla.org/observer-service;1");
if (obsServ)
obsServ->AddObserver(this, "quit-application", true);
if (aPixbuf)
notify_notification_set_icon_from_pixbuf(mNotification, aPixbuf);
@ -277,13 +283,8 @@ nsAlertsIconListener::Observe(nsISupports *aSubject, const char *aTopic,
}
nsresult
nsAlertsIconListener::InitAlertAsync(const nsAString & aImageUrl,
const nsAString & aAlertTitle,
const nsAString & aAlertText,
bool aAlertTextClickable,
const nsAString & aAlertCookie,
nsIObserver * aAlertListener,
bool aInPrivateBrowsing)
nsAlertsIconListener::InitAlertAsync(nsIAlertNotification* aAlert,
nsIObserver* aAlertListener)
{
if (!libNotifyHandle)
return NS_ERROR_FAILURE;
@ -335,27 +336,38 @@ nsAlertsIconListener::InitAlertAsync(const nsAString & aImageUrl,
return NS_ERROR_FAILURE;
}
if (!gHasActions && aAlertTextClickable)
nsresult rv = aAlert->GetTextClickable(&mAlertHasAction);
NS_ENSURE_SUCCESS(rv, rv);
if (!gHasActions && mAlertHasAction)
return NS_ERROR_FAILURE; // No good, fallback to XUL
nsCOMPtr<nsIObserverService> obsServ =
do_GetService("@mozilla.org/observer-service;1");
if (obsServ)
obsServ->AddObserver(this, "quit-application", true);
nsAutoString title;
rv = aAlert->GetTitle(title);
NS_ENSURE_SUCCESS(rv, rv);
// Workaround for a libnotify bug - blank titles aren't dealt with
// properly so we use a space
if (aAlertTitle.IsEmpty()) {
if (title.IsEmpty()) {
mAlertTitle = NS_LITERAL_CSTRING(" ");
} else {
mAlertTitle = NS_ConvertUTF16toUTF8(aAlertTitle);
mAlertTitle = NS_ConvertUTF16toUTF8(title);
}
mAlertText = NS_ConvertUTF16toUTF8(aAlertText);
mAlertHasAction = aAlertTextClickable;
nsAutoString text;
rv = aAlert->GetText(text);
NS_ENSURE_SUCCESS(rv, rv);
mAlertText = NS_ConvertUTF16toUTF8(text);
mAlertListener = aAlertListener;
mAlertCookie = aAlertCookie;
return StartRequest(aImageUrl, aInPrivateBrowsing);
rv = aAlert->GetCookie(mAlertCookie);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString imageUrl;
rv = aAlert->GetImageURL(imageUrl);
NS_ENSURE_SUCCESS(rv, rv);
bool inPrivateBrowsing;
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
NS_ENSURE_SUCCESS(rv, rv);
return StartRequest(imageUrl, inPrivateBrowsing);
}

View File

@ -15,6 +15,7 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
class imgIRequest;
class nsIAlertNotification;
struct NotifyNotification;
@ -29,13 +30,8 @@ public:
nsAlertsIconListener();
nsresult InitAlertAsync(const nsAString & aImageUrl,
const nsAString & aAlertTitle,
const nsAString & aAlertText,
bool aAlertTextClickable,
const nsAString & aAlertCookie,
nsIObserver * aAlertListener,
bool aInPrivateBrowsing);
nsresult InitAlertAsync(nsIAlertNotification* aAlert,
nsIObserver* aAlertListener);
void SendCallback();
void SendClosed();

View File

@ -3,6 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsComponentManagerUtils.h"
#include "nsXULAppAPI.h"
#include "nsSystemAlertsService.h"
#include "nsAlertsIconListener.h"
@ -40,12 +41,27 @@ NS_IMETHODIMP nsSystemAlertsService::ShowAlertNotification(const nsAString & aIm
nsIPrincipal * aPrincipal,
bool aInPrivateBrowsing)
{
nsCOMPtr<nsIAlertNotification> alert =
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
aAlertText, aAlertTextClickable,
aAlertCookie, aBidi, aLang, aData,
aPrincipal, aInPrivateBrowsing);
NS_ENSURE_SUCCESS(rv, rv);
return ShowAlert(alert, aAlertListener);
}
NS_IMETHODIMP nsSystemAlertsService::ShowAlert(nsIAlertNotification* aAlert,
nsIObserver* aAlertListener)
{
NS_ENSURE_ARG(aAlert);
RefPtr<nsAlertsIconListener> alertListener = new nsAlertsIconListener();
if (!alertListener)
return NS_ERROR_OUT_OF_MEMORY;
return alertListener->InitAlertAsync(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
aAlertCookie, aAlertListener, aInPrivateBrowsing);
return alertListener->InitAlertAsync(aAlert, aAlertListener);
}
NS_IMETHODIMP nsSystemAlertsService::CloseAlert(const nsAString& aAlertName,

View File

@ -11,6 +11,7 @@
#include "nsNetUtil.h"
#include "imgLoader.h"
#import "nsCocoaUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsObjCExceptions.h"
#include "nsString.h"
@ -240,15 +241,39 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
const nsAString & aData,
nsIPrincipal * aPrincipal,
bool aInPrivateBrowsing)
{
nsCOMPtr<nsIAlertNotification> alert =
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
aAlertText, aAlertTextClickable,
aAlertCookie, aBidi, aLang, aData,
aPrincipal, aInPrivateBrowsing);
NS_ENSURE_SUCCESS(rv, rv);
return ShowAlert(alert, aAlertListener);
}
NS_IMETHODIMP
OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert,
nsIObserver* aAlertListener)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NS_ENSURE_ARG(aAlert);
Class unClass = NSClassFromString(@"NSUserNotification");
id<FakeNSUserNotification> notification = [[unClass alloc] init];
notification.title = nsCocoaUtils::ToNSString(aAlertTitle);
nsAutoString title;
nsresult rv = aAlert->GetTitle(title);
NS_ENSURE_SUCCESS(rv, rv);
notification.title = nsCocoaUtils::ToNSString(title);
nsCOMPtr<nsIPrincipal> principal;
rv = aAlert->GetPrincipal(getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString hostPort;
nsAlertsUtils::GetSourceHostPort(aPrincipal, hostPort);
nsAlertsUtils::GetSourceHostPort(principal, hostPort);
nsCOMPtr<nsIStringBundle> bundle;
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle));
@ -263,12 +288,16 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
notification.subtitle = nsCocoaUtils::ToNSString(notificationSource);
}
notification.informativeText = nsCocoaUtils::ToNSString(aAlertText);
nsAutoString text;
rv = aAlert->GetText(text);
NS_ENSURE_SUCCESS(rv, rv);
notification.informativeText = nsCocoaUtils::ToNSString(text);
notification.soundName = NSUserNotificationDefaultSoundName;
notification.hasActionButton = NO;
// If this is not an application/extension alert, show additional actions dealing with permissions.
if (nsAlertsUtils::IsActionablePrincipal(aPrincipal)) {
if (nsAlertsUtils::IsActionablePrincipal(principal)) {
if (bundle) {
nsXPIDLString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle;
bundle->GetStringFromName(MOZ_UTF16("closeButton.title"),
@ -307,24 +336,39 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
}
}
}
NSString *alertName = nsCocoaUtils::ToNSString(aAlertName);
nsAutoString name;
rv = aAlert->GetName(name);
NS_ENSURE_SUCCESS(rv, rv);
NSString *alertName = nsCocoaUtils::ToNSString(name);
if (!alertName) {
return NS_ERROR_FAILURE;
}
notification.userInfo = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:alertName, nil]
forKeys:[NSArray arrayWithObjects:@"name", nil]];
OSXNotificationInfo *osxni = new OSXNotificationInfo(alertName, aAlertListener, aAlertCookie);
nsAutoString cookie;
rv = aAlert->GetCookie(cookie);
NS_ENSURE_SUCCESS(rv, rv);
OSXNotificationInfo *osxni = new OSXNotificationInfo(alertName, aAlertListener, cookie);
nsAutoString imageUrl;
rv = aAlert->GetImageURL(imageUrl);
NS_ENSURE_SUCCESS(rv, rv);
bool inPrivateBrowsing;
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
NS_ENSURE_SUCCESS(rv, rv);
// Show the notification without waiting for an image if there is no icon URL or
// notification icons are not supported on this version of OS X.
if (aImageUrl.IsEmpty() || ![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
if (imageUrl.IsEmpty() || ![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
CloseAlertCocoaString(alertName);
mActiveAlerts.AppendElement(osxni);
[GetNotificationCenter() deliverNotification:notification];
[notification release];
if (aAlertListener) {
aAlertListener->Observe(nullptr, "alertshow", PromiseFlatString(aAlertCookie).get());
aAlertListener->Observe(nullptr, "alertshow", cookie.get());
}
} else {
mPendingAlerts.AppendElement(osxni);
@ -332,17 +376,17 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
RefPtr<imgLoader> il = imgLoader::GetInstance();
if (il) {
nsCOMPtr<nsIURI> imageUri;
NS_NewURI(getter_AddRefs(imageUri), aImageUrl);
NS_NewURI(getter_AddRefs(imageUri), imageUrl);
if (imageUri) {
nsresult rv = il->LoadImage(imageUri, nullptr, nullptr,
mozilla::net::RP_Default,
aPrincipal, nullptr,
this, nullptr,
aInPrivateBrowsing ? nsIRequest::LOAD_ANONYMOUS :
nsIRequest::LOAD_NORMAL,
nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE,
EmptyString(),
getter_AddRefs(osxni->mIconRequest));
rv = il->LoadImage(imageUri, nullptr, nullptr,
mozilla::net::RP_Default,
principal, nullptr,
this, nullptr,
inPrivateBrowsing ? nsIRequest::LOAD_ANONYMOUS :
nsIRequest::LOAD_NORMAL,
nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE,
EmptyString(),
getter_AddRefs(osxni->mIconRequest));
if (NS_SUCCEEDED(rv)) {
// Set a timer for six seconds. If we don't have an icon by the time this
// goes off then we go ahead without an icon.