зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1781929 - Part 1: Handle toast notifications from background tasks specially. r=nrishel
In background task mode: 1. Re-launch Firefox into the default browsing profile, not the (possibly ephemeral) background task profile. 2. Don't show the in-product notification settings, which won't apply to the relevant Firefox profile. Differential Revision: https://phabricator.services.mozilla.com/D155908
This commit is contained in:
Родитель
b1c91cad45
Коммит
c2e7a9b4e8
|
@ -11,6 +11,9 @@
|
|||
#include "imgIContainer.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#ifdef MOZ_BACKGROUNDTASKS
|
||||
# include "mozilla/BackgroundTasks.h"
|
||||
#endif
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/Tokenizer.h"
|
||||
|
@ -21,6 +24,8 @@
|
|||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsIDUtils.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIToolkitProfile.h"
|
||||
#include "nsIToolkitProfileService.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
|
@ -171,13 +176,42 @@ static Result<nsString, nsresult> GetLaunchArgument() {
|
|||
// `program` argument.
|
||||
launchArg += u"program\n"_ns MOZ_APP_NAME;
|
||||
|
||||
// `profile` argument
|
||||
// `profile` argument.
|
||||
nsCOMPtr<nsIFile> profDir;
|
||||
MOZ_TRY(NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(profDir)));
|
||||
nsAutoString profilePath;
|
||||
MOZ_TRY(profDir->GetPath(profilePath));
|
||||
launchArg += u"\nprofile\n"_ns + profilePath;
|
||||
bool wantCurrentProfile = true;
|
||||
#ifdef MOZ_BACKGROUNDTASKS
|
||||
if (BackgroundTasks::IsBackgroundTaskMode()) {
|
||||
// Notifications popped from a background task want to invoke Firefox with a
|
||||
// different profile -- the default browsing profile. We'd prefer to not
|
||||
// specify a profile, so that the Firefox invoked by the notification server
|
||||
// chooses its default profile, but this might pop the profile chooser in
|
||||
// some configurations.
|
||||
wantCurrentProfile = false;
|
||||
|
||||
nsCOMPtr<nsIToolkitProfileService> profileSvc =
|
||||
do_GetService(NS_PROFILESERVICE_CONTRACTID);
|
||||
if (profileSvc) {
|
||||
nsCOMPtr<nsIToolkitProfile> defaultProfile;
|
||||
nsresult rv =
|
||||
profileSvc->GetDefaultProfile(getter_AddRefs(defaultProfile));
|
||||
if (NS_SUCCEEDED(rv) && defaultProfile) {
|
||||
// Not all installations have a default profile. But if one is set,
|
||||
// then it should have a profile directory.
|
||||
MOZ_TRY(defaultProfile->GetRootDir(getter_AddRefs(profDir)));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (wantCurrentProfile) {
|
||||
MOZ_TRY(NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(profDir)));
|
||||
}
|
||||
|
||||
if (profDir) {
|
||||
nsAutoString profilePath;
|
||||
MOZ_TRY(profDir->GetPath(profilePath));
|
||||
launchArg += u"\nprofile\n"_ns + profilePath;
|
||||
}
|
||||
|
||||
return launchArg;
|
||||
}
|
||||
|
@ -426,11 +460,23 @@ ComPtr<IXmlDocument> ToastNotificationHandler::CreateToastXmlDocument() {
|
|||
u"snooze"_ns, u"contextmenu"_ns);
|
||||
}
|
||||
|
||||
nsAutoString settingsButtonTitle;
|
||||
bundle->GetStringFromName("webActions.settings.label", settingsButtonTitle);
|
||||
success = AddActionNode(toastXml, actionsNode, settingsButtonTitle, launchArg,
|
||||
u"settings"_ns, u"contextmenu"_ns);
|
||||
NS_ENSURE_TRUE(success, nullptr);
|
||||
bool wantSettings = true;
|
||||
#ifdef MOZ_BACKGROUNDTASKS
|
||||
if (BackgroundTasks::IsBackgroundTaskMode()) {
|
||||
// Notifications popped from a background task want to invoke Firefox with a
|
||||
// different profile -- the default browsing profile. Don't link to Firefox
|
||||
// settings in some different profile: the relevant Firefox settings won't
|
||||
// take effect.
|
||||
wantSettings = false;
|
||||
}
|
||||
#endif
|
||||
if (MOZ_LIKELY(wantSettings)) {
|
||||
nsAutoString settingsButtonTitle;
|
||||
bundle->GetStringFromName("webActions.settings.label", settingsButtonTitle);
|
||||
success = AddActionNode(toastXml, actionsNode, settingsButtonTitle,
|
||||
launchArg, u"settings"_ns, u"contextmenu"_ns);
|
||||
NS_ENSURE_TRUE(success, nullptr);
|
||||
}
|
||||
|
||||
for (const auto& action : mActions) {
|
||||
// Bug 1778596: include per-action icon from image URL.
|
||||
|
|
|
@ -56,21 +56,30 @@ function makeAlert(options) {
|
|||
return alert;
|
||||
}
|
||||
|
||||
function testAlert(serverEnabled) {
|
||||
function testAlert(when, { serverEnabled, profD, isBackgroundTaskMode } = {}) {
|
||||
let argumentString = argument => {
|
||||
// 
 is "\n".
|
||||
let s = ``;
|
||||
if (serverEnabled) {
|
||||
s += `program
${AppConstants.MOZ_APP_NAME}
profile
${gProfD.path}`;
|
||||
s += `program
${AppConstants.MOZ_APP_NAME}`;
|
||||
} else {
|
||||
s += `invalid key
invalid value`;
|
||||
}
|
||||
if (serverEnabled && profD) {
|
||||
s += `
profile
${profD.path}`;
|
||||
}
|
||||
if (argument) {
|
||||
s += `
action
${argument}`;
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
let settingsAction = isBackgroundTaskMode
|
||||
? ""
|
||||
: `<action content="Notification settings" arguments="${argumentString(
|
||||
"settings"
|
||||
)}" placement="contextmenu"/>`;
|
||||
|
||||
let alertsService = Cc["@mozilla.org/system-alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService)
|
||||
.QueryInterface(Ci.nsIWindowsAlertsService);
|
||||
|
@ -85,32 +94,40 @@ function testAlert(serverEnabled) {
|
|||
];
|
||||
|
||||
let alert = makeAlert({ name, title, text });
|
||||
let expected = `<toast launch="${argumentString()}"><visual><binding template="ToastText03"><text id="1">title</text><text id="2">text</text></binding></visual><actions><action content="Notification settings" arguments="${argumentString(
|
||||
"settings"
|
||||
)}" placement="contextmenu"/></actions></toast>`;
|
||||
Assert.equal(expected, alertsService.getXmlStringForWindowsAlert(alert));
|
||||
let expected = `<toast launch="${argumentString()}"><visual><binding template="ToastText03"><text id="1">title</text><text id="2">text</text></binding></visual><actions>${settingsAction}</actions></toast>`;
|
||||
Assert.equal(
|
||||
expected.replace("<actions></actions>", "<actions/>"),
|
||||
alertsService.getXmlStringForWindowsAlert(alert),
|
||||
when
|
||||
);
|
||||
|
||||
alert = makeAlert({ name, title, text, imageURL });
|
||||
expected = `<toast launch="${argumentString()}"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/><text id="1">title</text><text id="2">text</text></binding></visual><actions><action content="Notification settings" arguments="${argumentString(
|
||||
"settings"
|
||||
)}" placement="contextmenu"/></actions></toast>`;
|
||||
Assert.equal(expected, alertsService.getXmlStringForWindowsAlert(alert));
|
||||
expected = `<toast launch="${argumentString()}"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/><text id="1">title</text><text id="2">text</text></binding></visual><actions>${settingsAction}</actions></toast>`;
|
||||
Assert.equal(
|
||||
expected.replace("<actions></actions>", "<actions/>"),
|
||||
alertsService.getXmlStringForWindowsAlert(alert),
|
||||
when
|
||||
);
|
||||
|
||||
alert = makeAlert({ name, title, text, imageURL, requireInteraction: true });
|
||||
expected = `<toast scenario="reminder" launch="${argumentString()}"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/><text id="1">title</text><text id="2">text</text></binding></visual><actions><action content="Notification settings" arguments="${argumentString(
|
||||
"settings"
|
||||
)}" placement="contextmenu"/></actions></toast>`;
|
||||
Assert.equal(expected, alertsService.getXmlStringForWindowsAlert(alert));
|
||||
expected = `<toast scenario="reminder" launch="${argumentString()}"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/><text id="1">title</text><text id="2">text</text></binding></visual><actions>${settingsAction}</actions></toast>`;
|
||||
Assert.equal(
|
||||
expected.replace("<actions></actions>", "<actions/>"),
|
||||
alertsService.getXmlStringForWindowsAlert(alert),
|
||||
when
|
||||
);
|
||||
|
||||
alert = makeAlert({ name, title, text, imageURL, actions });
|
||||
expected = `<toast launch="${argumentString()}"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/><text id="1">title</text><text id="2">text</text></binding></visual><actions><action content="Notification settings" arguments="${argumentString(
|
||||
"settings"
|
||||
)}" placement="contextmenu"/><action content="title1" arguments="${argumentString(
|
||||
expected = `<toast launch="${argumentString()}"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/><text id="1">title</text><text id="2">text</text></binding></visual><actions>${settingsAction}<action content="title1" arguments="${argumentString(
|
||||
"action1"
|
||||
)}"/><action content="title2" arguments="${argumentString(
|
||||
"action2"
|
||||
)}"/></actions></toast>`;
|
||||
Assert.equal(expected, alertsService.getXmlStringForWindowsAlert(alert));
|
||||
Assert.equal(
|
||||
expected.replace("<actions></actions>", "<actions/>"),
|
||||
alertsService.getXmlStringForWindowsAlert(alert),
|
||||
when
|
||||
);
|
||||
|
||||
// Chrome privileged alerts can use `windowsSystemActivationType`.
|
||||
let systemActions = [
|
||||
|
@ -134,10 +151,12 @@ function testAlert(serverEnabled) {
|
|||
principal: systemPrincipal,
|
||||
actions: systemActions,
|
||||
});
|
||||
expected = `<toast launch="${argumentString()}"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/><text id="1">title</text><text id="2">text</text></binding></visual><actions><action content="Notification settings" arguments="${argumentString(
|
||||
"settings"
|
||||
)}" placement="contextmenu"/><action content="dismissTitle" arguments="dismiss" activationType="system"/><action content="snoozeTitle" arguments="snooze" activationType="system"/></actions></toast>`;
|
||||
Assert.equal(expected, alertsService.getXmlStringForWindowsAlert(alert));
|
||||
expected = `<toast launch="${argumentString()}"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/><text id="1">title</text><text id="2">text</text></binding></visual><actions>${settingsAction}<action content="dismissTitle" arguments="dismiss" activationType="system"/><action content="snoozeTitle" arguments="snooze" activationType="system"/></actions></toast>`;
|
||||
Assert.equal(
|
||||
expected,
|
||||
alertsService.getXmlStringForWindowsAlert(alert),
|
||||
when
|
||||
);
|
||||
|
||||
// But content unprivileged alerts can't use `windowsSystemActivationType`.
|
||||
let launchUrl = "https://example.com/foo/bar.html";
|
||||
|
@ -157,31 +176,81 @@ function testAlert(serverEnabled) {
|
|||
});
|
||||
expected = `<toast launch="${argumentString()}"><visual><binding template="ToastImageAndText04"><image id="1" src="file:///image.png"/><text id="1">title</text><text id="2">text</text><text id="3" placement="attribution">via example.com</text></binding></visual><actions><action content="Disable notifications from example.com" arguments="${argumentString(
|
||||
"snooze"
|
||||
)}" placement="contextmenu"/><action content="Notification settings" arguments="${argumentString(
|
||||
"settings"
|
||||
)}" placement="contextmenu"/><action content="dismissTitle" arguments="${argumentString(
|
||||
)}" placement="contextmenu"/>${settingsAction}<action content="dismissTitle" arguments="${argumentString(
|
||||
"dismiss"
|
||||
)}"/><action content="snoozeTitle" arguments="${argumentString(
|
||||
"snooze"
|
||||
)}"/></actions></toast>`;
|
||||
Assert.equal(expected, alertsService.getXmlStringForWindowsAlert(alert));
|
||||
Assert.equal(
|
||||
expected,
|
||||
alertsService.getXmlStringForWindowsAlert(alert),
|
||||
when
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async () => {
|
||||
Services.prefs.clearUserPref(
|
||||
"alerts.useSystemBackend.windows.notificationserver.enabled"
|
||||
);
|
||||
testAlert(false);
|
||||
testAlert("when notification server pref is unset (i.e., default)", {
|
||||
profD: gProfD,
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref(
|
||||
"alerts.useSystemBackend.windows.notificationserver.enabled",
|
||||
false
|
||||
);
|
||||
testAlert(false);
|
||||
testAlert("when notification server pref is false", { profD: gProfD });
|
||||
|
||||
Services.prefs.setBoolPref(
|
||||
"alerts.useSystemBackend.windows.notificationserver.enabled",
|
||||
true
|
||||
);
|
||||
testAlert(true);
|
||||
testAlert("when notification server pref is true", {
|
||||
serverEnabled: true,
|
||||
profD: gProfD,
|
||||
});
|
||||
});
|
||||
|
||||
let condition = {
|
||||
skip_if: () => !AppConstants.MOZ_BACKGROUNDTASKS,
|
||||
};
|
||||
|
||||
add_task(condition, async () => {
|
||||
const bts = Cc["@mozilla.org/backgroundtasks;1"]?.getService(
|
||||
Ci.nsIBackgroundTasks
|
||||
);
|
||||
|
||||
// Pretend that this is a background task.
|
||||
bts.overrideBackgroundTaskNameForTesting("taskname");
|
||||
|
||||
Services.prefs.setBoolPref(
|
||||
"alerts.useSystemBackend.windows.notificationserver.enabled",
|
||||
true
|
||||
);
|
||||
testAlert(
|
||||
"when notification server pref is true in background task, no default profile",
|
||||
{ serverEnabled: true, isBackgroundTaskMode: true }
|
||||
);
|
||||
|
||||
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
|
||||
Ci.nsIToolkitProfileService
|
||||
);
|
||||
|
||||
let profilePath = do_get_profile();
|
||||
profilePath.append(`test_windows_alert_service`);
|
||||
let profile = profileService.createUniqueProfile(
|
||||
profilePath,
|
||||
"test_windows_alert_service"
|
||||
);
|
||||
|
||||
profileService.defaultProfile = profile;
|
||||
|
||||
testAlert(
|
||||
"when notification server pref is true in background task, default profile",
|
||||
{ serverEnabled: true, isBackgroundTaskMode: true, profD: profilePath }
|
||||
);
|
||||
|
||||
// No longer a background task,
|
||||
bts.overrideBackgroundTaskNameForTesting("");
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче