135 lines
4.2 KiB
JavaScript
135 lines
4.2 KiB
JavaScript
/* 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/. */
|
|
|
|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
|
|
EnrollmentType: "resource://nimbus/ExperimentAPI.sys.mjs",
|
|
RemoteL10n: "resource:///modules/asrouter/RemoteL10n.sys.mjs",
|
|
});
|
|
|
|
XPCOMUtils.defineLazyServiceGetters(lazy, {
|
|
AlertsService: ["@mozilla.org/alerts-service;1", "nsIAlertsService"],
|
|
});
|
|
|
|
export const ToastNotification = {
|
|
// Allow testing to stub the alerts service.
|
|
get AlertsService() {
|
|
return lazy.AlertsService;
|
|
},
|
|
|
|
sendUserEventTelemetry(event, message, dispatch) {
|
|
const ping = {
|
|
message_id: message.id,
|
|
event,
|
|
};
|
|
dispatch({
|
|
type: "TOAST_NOTIFICATION_TELEMETRY",
|
|
data: { action: "toast_notification_user_event", ...ping },
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Show a toast notification.
|
|
* @param message Message containing content to show.
|
|
* @param dispatch A function to dispatch resulting actions.
|
|
* @return boolean value capturing if toast notification was displayed.
|
|
*/
|
|
async showToastNotification(message, dispatch) {
|
|
let { content } = message;
|
|
let title = await lazy.RemoteL10n.formatLocalizableText(content.title);
|
|
let body = await lazy.RemoteL10n.formatLocalizableText(content.body);
|
|
|
|
// The only link between background task message experiment and user
|
|
// re-engagement via the notification is the associated "tag". Said tag is
|
|
// usually controlled by the message content, but for message experiments,
|
|
// we want to avoid a missing tag and to ensure a deterministic tag for
|
|
// easier analysis, including across branches.
|
|
let { tag } = content;
|
|
|
|
let experimentMetadata =
|
|
lazy.NimbusFeatures.backgroundTaskMessage.getEnrollmentMetadata(
|
|
lazy.EnrollmentType.EXPERIMENT
|
|
);
|
|
|
|
if (experimentMetadata) {
|
|
// Like `my-experiment:my-branch`.
|
|
tag = `${experimentMetadata.slug}:${experimentMetadata.branch}`;
|
|
}
|
|
|
|
// There are two events named `IMPRESSION` the first one refers to telemetry
|
|
// while the other refers to ASRouter impressions used for the frequency cap
|
|
this.sendUserEventTelemetry("IMPRESSION", message, dispatch);
|
|
dispatch({ type: "IMPRESSION", data: message });
|
|
|
|
let alert = Cc["@mozilla.org/alert-notification;1"].createInstance(
|
|
Ci.nsIAlertNotification
|
|
);
|
|
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
|
alert.init(
|
|
tag,
|
|
content.image_url
|
|
? Services.urlFormatter.formatURL(content.image_url)
|
|
: content.image_url,
|
|
title,
|
|
body,
|
|
true /* aTextClickable */,
|
|
content.data,
|
|
null /* aDir */,
|
|
null /* aLang */,
|
|
null /* aData */,
|
|
systemPrincipal,
|
|
null /* aInPrivateBrowsing */,
|
|
content.requireInteraction
|
|
);
|
|
|
|
if (content.actions) {
|
|
let actions = Cu.cloneInto(content.actions, {});
|
|
for (let action of actions) {
|
|
if (action.title) {
|
|
action.title = await lazy.RemoteL10n.formatLocalizableText(
|
|
action.title
|
|
);
|
|
}
|
|
if (action.launch_action) {
|
|
action.opaqueRelaunchData = JSON.stringify(action.launch_action);
|
|
delete action.launch_action;
|
|
}
|
|
}
|
|
alert.actions = actions;
|
|
}
|
|
|
|
// Populate `opaqueRelaunchData`, prefering `launch_action` if given,
|
|
// falling back to `launch_url` if given.
|
|
let relaunchAction = content.launch_action;
|
|
if (!relaunchAction && content.launch_url) {
|
|
relaunchAction = {
|
|
type: "OPEN_URL",
|
|
data: {
|
|
args: content.launch_url,
|
|
where: "tab",
|
|
},
|
|
};
|
|
}
|
|
if (relaunchAction) {
|
|
alert.opaqueRelaunchData = JSON.stringify(relaunchAction);
|
|
}
|
|
|
|
let shownPromise = Promise.withResolvers();
|
|
let obs = (subject, topic) => {
|
|
if (topic === "alertshow") {
|
|
shownPromise.resolve();
|
|
}
|
|
};
|
|
|
|
this.AlertsService.showAlert(alert, obs);
|
|
|
|
await shownPromise;
|
|
|
|
return true;
|
|
},
|
|
};
|