Files
tubestation/browser/components/newtab/lib/ToastNotification.jsm
Nick Alexander 98d1c4c0c2 Bug 1804988 - Determine toast notification tag from experiment:branch slug in backgroundTaskMessage experiments. r=barret
This commit uses a "pull" approach, where the experiment details are
fished at presentation-time and the content `tag` updated.

A few notes:

- With this approach, the update function is pushed down to the leaf
  node (the toast notification presentation layer).  It would be nice to
  do this at the experiment layer, but that layer doesn't resolve the
  presentation layer at this time, so it would perhaps violate the
  abstraction to lift the work higher.

- No effort has been made to mark `tag` as invalid in the messaging
  experiment schemas.  At this time, there's no provision for fields
  accepted at the presentation layer (`ToastNotification.schema.json`)
  but not at the experiment layer aggregating
  presentations (`BackgroundTaskMessagingExperiment.schema.json`,
  `MessagingExperiment.schema.json`).  It's likely possible to arrange
  this but not worth the effort at this time.

- The actual tag displayed is not captured in the message as it flows
  through ASRouter.  This is not likely to pose a problem.

- The actual tag displayed might be `optin-...`, potentially
  complicating data analysis.  Since it's essentially impossible for
  regular users to opt-in to _background task_ messages, that's not a
  pressing concern.

Differential Revision: https://phabricator.services.mozilla.com/D164508
2022-12-14 18:52:34 +00:00

119 lines
3.6 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/. */
"use strict";
const { XPCOMUtils } = ChromeUtils.importESModule(
"resource://gre/modules/XPCOMUtils.sys.mjs"
);
const lazy = {};
XPCOMUtils.defineLazyModuleGetters(lazy, {
ExperimentAPI: "resource://nimbus/ExperimentAPI.jsm",
RemoteL10n: "resource://activity-stream/lib/RemoteL10n.jsm",
});
XPCOMUtils.defineLazyServiceGetters(lazy, {
AlertsService: ["@mozilla.org/alerts-service;1", "nsIAlertsService"],
});
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.ExperimentAPI.getExperimentMetaData({
featureId: "backgroundTaskMessage",
}) || {};
if (
experimentMetadata?.active &&
experimentMetadata?.slug &&
experimentMetadata?.branch?.slug
) {
// Like `my-experiment:my-branch`.
tag = `${experimentMetadata?.slug}:${experimentMetadata?.branch?.slug}`;
}
// 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
);
}
}
alert.actions = actions;
}
if (content.launch_url) {
alert.launchURL = Services.urlFormatter.formatURL(content.launch_url);
}
this.AlertsService.showAlert(alert);
return true;
},
};
const EXPORTED_SYMBOLS = ["ToastNotification"];