mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
Bug 1685525 - Update or add a trigger capable of targeting newtab/homepage for messages r=k88hudson
Differential Revision: https://phabricator.services.mozilla.com/D101936
This commit is contained in:
parent
8bee559e1a
commit
96e52c74a2
@ -15,6 +15,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
ASRouter: "resource://activity-stream/lib/ASRouter.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
@ -35,6 +36,14 @@ class AboutNewTabParent extends JSWindowActorParent {
|
||||
async receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "DefaultBrowserNotification":
|
||||
ASRouter.waitForInitialized.then(() =>
|
||||
ASRouter.sendTriggerMessage({
|
||||
browser: this.browsingContext.top.embedderElement,
|
||||
// triggerId and triggerContext
|
||||
id: "defaultBrowserCheck",
|
||||
context: { source: "newtab" },
|
||||
})
|
||||
);
|
||||
await DefaultBrowserNotification.maybeShow(
|
||||
this.browsingContext.top.embedderElement,
|
||||
this.browsingContext.topChromeWindow?.getShellService()
|
||||
|
@ -1394,7 +1394,7 @@ pref("browser.newtabpage.activity-stream.asrouter.providers.message-groups", "{\
|
||||
// this page over http opens us up to a man-in-the-middle attack that we'd rather not face. If you are a downstream
|
||||
// repackager of this code using an alternate snippet url, please keep your users safe
|
||||
pref("browser.newtabpage.activity-stream.asrouter.providers.snippets", "{\"id\":\"snippets\",\"enabled\":true,\"type\":\"remote\",\"url\":\"https://snippets.cdn.mozilla.net/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/\",\"updateCycleInMs\":14400000}");
|
||||
pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "{\"id\":\"messaging-experiments\",\"enabled\":true,\"type\":\"remote-experiments\",\"messageGroups\":[\"cfr\",\"whats-new-panel\",\"moments-page\",\"snippets\",\"cfr-fxa\",\"aboutwelcome\"],\"updateCycleInMs\":3600000}");
|
||||
pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "{\"id\":\"messaging-experiments\",\"enabled\":true,\"type\":\"remote-experiments\",\"messageGroups\":[\"cfr\",\"whats-new-panel\",\"moments-page\",\"snippets\",\"cfr-fxa\",\"aboutwelcome\",\"infobar\"],\"updateCycleInMs\":3600000}");
|
||||
|
||||
// ASRouter user prefs
|
||||
pref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", true);
|
||||
|
@ -25,6 +25,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
ASRouterDefaultConfig:
|
||||
"resource://activity-stream/lib/ASRouterDefaultConfig.jsm",
|
||||
ASRouterNewTabHook: "resource://activity-stream/lib/ASRouterNewTabHook.jsm",
|
||||
ASRouter: "resource://activity-stream/lib/ASRouter.jsm",
|
||||
AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
|
||||
Blocklist: "resource://gre/modules/Blocklist.jsm",
|
||||
BookmarkHTMLUtils: "resource://gre/modules/BookmarkHTMLUtils.jsm",
|
||||
@ -43,6 +44,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
"resource:///modules/DownloadsViewableInternally.jsm",
|
||||
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
|
||||
ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
|
||||
ExperimentAPI: "resource://messaging-system/experiments/ExperimentAPI.jsm",
|
||||
FeatureGate: "resource://featuregates/FeatureGate.jsm",
|
||||
FirefoxMonitor: "resource:///modules/FirefoxMonitor.jsm",
|
||||
FxAccounts: "resource://gre/modules/FxAccounts.jsm",
|
||||
@ -3852,21 +3854,44 @@ BrowserGlue.prototype = {
|
||||
},
|
||||
|
||||
_maybeShowDefaultBrowserPrompt() {
|
||||
DefaultBrowserCheck.willCheckDefaultBrowser(/* isStartupCheck */ true).then(
|
||||
async willPrompt => {
|
||||
let { DefaultBrowserNotification } = ChromeUtils.import(
|
||||
"resource:///actors/AboutNewTabParent.jsm",
|
||||
{}
|
||||
);
|
||||
if (willPrompt) {
|
||||
// Prevent the related notification from appearing and
|
||||
// show the modal prompt.
|
||||
DefaultBrowserNotification.notifyModalDisplayed();
|
||||
let win = BrowserWindowTracker.getTopWindow();
|
||||
DefaultBrowserCheck.prompt(win);
|
||||
}
|
||||
Promise.all([
|
||||
DefaultBrowserCheck.willCheckDefaultBrowser(/* isStartupCheck */ true),
|
||||
ExperimentAPI.ready,
|
||||
]).then(async ([willPrompt]) => {
|
||||
let { DefaultBrowserNotification } = ChromeUtils.import(
|
||||
"resource:///actors/AboutNewTabParent.jsm",
|
||||
{}
|
||||
);
|
||||
let isFeatureEnabled = false;
|
||||
try {
|
||||
isFeatureEnabled = ExperimentAPI.getExperiment({
|
||||
featureId: "infobar",
|
||||
sendExposurePing: false,
|
||||
})?.branch.feature.enabled;
|
||||
} catch (e) {}
|
||||
if (willPrompt) {
|
||||
// Prevent the related notification from appearing and
|
||||
// show the modal prompt.
|
||||
DefaultBrowserNotification.notifyModalDisplayed();
|
||||
}
|
||||
);
|
||||
// If no experiment go ahead with default experience
|
||||
if (willPrompt && !isFeatureEnabled) {
|
||||
let win = BrowserWindowTracker.getTopWindow();
|
||||
DefaultBrowserCheck.prompt(win);
|
||||
}
|
||||
// If in experiment notify ASRouter to dispatch message
|
||||
if (isFeatureEnabled) {
|
||||
ASRouter.waitForInitialized.then(() =>
|
||||
ASRouter.sendTriggerMessage({
|
||||
browser: BrowserWindowTracker.getTopWindow()?.gBrowser
|
||||
.selectedBrowser,
|
||||
// triggerId and triggerContext
|
||||
id: "defaultBrowserCheck",
|
||||
context: { willShowDefaultPrompt: willPrompt },
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -14,6 +14,7 @@ const MESSAGE_TYPE_LIST = [
|
||||
"TOOLBAR_BADGE_TELEMETRY",
|
||||
"TOOLBAR_PANEL_TELEMETRY",
|
||||
"MOMENTS_PAGE_TELEMETRY",
|
||||
"INFOBAR_TELEMETRY",
|
||||
"AS_ROUTER_TELEMETRY_USER_EVENT",
|
||||
|
||||
// Admin types
|
||||
|
@ -48,7 +48,8 @@ Please note that some targeting attributes require stricter controls on the tele
|
||||
* [profileRestartCount](#profilerestartcount)
|
||||
* [homePageSettings](#homepagesettings)
|
||||
* [newtabSettings](#newtabsettings)
|
||||
* [isFissionExperimentEnabled](#isFissionExperimentEnabled)
|
||||
* [isFissionExperimentEnabled](#isfissionexperimentenabled)
|
||||
* [activeNotifications](#activenotifications)
|
||||
|
||||
## Detailed usage
|
||||
|
||||
@ -820,3 +821,8 @@ Object {
|
||||
### `isFissionExperimentEnabled`
|
||||
|
||||
A boolean. `true` if we're running Fission experiment, `false` otherwise.
|
||||
|
||||
### `activeNotifications`
|
||||
|
||||
True when an infobar style message is displayed or when the awesomebar is
|
||||
expanded to show a message (for example onboarding tips).
|
||||
|
@ -0,0 +1,96 @@
|
||||
{
|
||||
"title": "InfoBar",
|
||||
"description": "A template with an image, test and buttons.",
|
||||
"version": "1.0.0",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
"plainText": {
|
||||
"description": "Plain text (no HTML allowed)",
|
||||
"type": "string"
|
||||
},
|
||||
"linkUrl": {
|
||||
"description": "Target for links or buttons",
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Should the message be global (persisted across tabs) or local (disappear when switching to a different tab).",
|
||||
"enum": ["global", "tab"]
|
||||
},
|
||||
"text": {
|
||||
"description": "The text show in the notification box.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Message shown in the location bar notification."
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"string_id": {
|
||||
"type": "string",
|
||||
"description": "Id of localized string for the location bar notification."
|
||||
}
|
||||
},
|
||||
"required": ["string_id"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"buttons": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"description": "The text label of the button.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Message content for the button."
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"string_id": {
|
||||
"type": "string",
|
||||
"description": "Id of localized string for the button."
|
||||
}
|
||||
},
|
||||
"required": ["string_id"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"primary": {
|
||||
"type": "boolean",
|
||||
"description": "Is this the primary button?"
|
||||
},
|
||||
"accessKey": {
|
||||
"type": "string",
|
||||
"description": "Keyboard shortcut letter."
|
||||
},
|
||||
"action": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Action dispatched by the button."
|
||||
},
|
||||
"data": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["label", "action", "accessKey"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["text", "buttons"]
|
||||
}
|
@ -966,6 +966,30 @@ as other CFR messages.
|
||||
}
|
||||
```
|
||||
|
||||
## InfoBar pings
|
||||
|
||||
This reports when the user interacts with the browser infobar (messaging area
|
||||
located at the top of the content area). Similar policy applied as for the
|
||||
What's New panel client_id is reported in all the channels.
|
||||
|
||||
```
|
||||
{
|
||||
"experiments" : {
|
||||
"exp1" : {
|
||||
"branch" : "treatment-a"
|
||||
}
|
||||
},
|
||||
"addon_version" : "20210115035053",
|
||||
"release_channel" : "release",
|
||||
"locale" : "en-US",
|
||||
"event" : ["IMPRESSION", "CLICK_PRIMARY_BUTTON", "CLICK_SECONDARY_BUTTON", "DISMISSED"],
|
||||
"client_id" : "c4beb4bf-4feb-9c4e-9587-9323b28c2e50",
|
||||
"version" : "86",
|
||||
"message_id" : "INFOBAR_ACTION_86",
|
||||
"browser_session_id" : "93714e76-9919-ca49-b697-5e7c09a1394f"
|
||||
}
|
||||
```
|
||||
|
||||
## Messaging-experiments pings
|
||||
|
||||
As the new experiment platform, the Messaging experiment manager is now managing & operating all the experiments of Firefox Messaging System, including the first-run experience (about:welcome), CFR, Whats-new-panel, Moments Page, and Snippets.
|
||||
|
@ -18,6 +18,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
ToolbarBadgeHub: "resource://activity-stream/lib/ToolbarBadgeHub.jsm",
|
||||
ToolbarPanelHub: "resource://activity-stream/lib/ToolbarPanelHub.jsm",
|
||||
MomentsPageHub: "resource://activity-stream/lib/MomentsPageHub.jsm",
|
||||
InfoBar: "resource://activity-stream/lib/InfoBar.jsm",
|
||||
ASRouterTargeting: "resource://activity-stream/lib/ASRouterTargeting.jsm",
|
||||
ASRouterPreferences: "resource://activity-stream/lib/ASRouterPreferences.jsm",
|
||||
TARGETING_PREFERENCES:
|
||||
@ -1056,14 +1057,14 @@ class _ASRouter {
|
||||
return targetingParameters;
|
||||
}
|
||||
|
||||
_handleTargetingError(type, error, message) {
|
||||
_handleTargetingError(error, message) {
|
||||
Cu.reportError(error);
|
||||
this.dispatchCFRAction(
|
||||
ac.ASRouterUserEvent({
|
||||
message_id: message.id,
|
||||
action: "asrouter_undesired_event",
|
||||
event: "TARGETING_EXPRESSION_ERROR",
|
||||
event_context: type,
|
||||
event_context: {},
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -1226,6 +1227,9 @@ class _ASRouter {
|
||||
case "update_action":
|
||||
MomentsPageHub.executeAction(message);
|
||||
break;
|
||||
case "infobar":
|
||||
InfoBar.showInfoBarMessage(browser, message, this.dispatchCFRAction);
|
||||
break;
|
||||
}
|
||||
|
||||
return { message };
|
||||
|
@ -30,6 +30,7 @@ class ASRouterParentProcessMessageHandler {
|
||||
|
||||
handleCFRAction({ type, data }, browser) {
|
||||
switch (type) {
|
||||
case msg.INFOBAR_TELEMETRY:
|
||||
case msg.TOOLBAR_BADGE_TELEMETRY:
|
||||
case msg.TOOLBAR_PANEL_TELEMETRY:
|
||||
case msg.MOMENTS_PAGE_TELEMETRY:
|
||||
|
@ -27,6 +27,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
TelemetrySession: "resource://gre/modules/TelemetrySession.jsm",
|
||||
HomePage: "resource:///modules/HomePage.jsm",
|
||||
AboutNewTab: "resource:///modules/AboutNewTab.jsm",
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
@ -636,6 +637,19 @@ const TargetingGetters = {
|
||||
Ci.nsIXULRuntime.eExperimentStatusTreatment
|
||||
);
|
||||
},
|
||||
get activeNotifications() {
|
||||
let window = BrowserWindowTracker.getTopWindow();
|
||||
|
||||
if (
|
||||
window.gURLBar.view.isOpen ||
|
||||
window.gHighPriorityNotificationBox.currentNotification ||
|
||||
window.gBrowser.getNotificationBox().currentNotification
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
this.ASRouterTargeting = {
|
||||
|
@ -1044,6 +1044,26 @@ const CFR_MESSAGES = [
|
||||
params: ["google.com", "www.google.com"],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "INFOBAR_ACTION_86",
|
||||
targeting: "false",
|
||||
template: "infobar",
|
||||
content: {
|
||||
type: "global",
|
||||
text: { string_id: "default-browser-notification-message" },
|
||||
buttons: [
|
||||
{
|
||||
label: { string_id: "default-browser-notification-button" },
|
||||
primary: true,
|
||||
accessKey: "O",
|
||||
action: {
|
||||
type: "SET_DEFAULT_BROWSER",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
trigger: { id: "defaultBrowserCheck" },
|
||||
},
|
||||
];
|
||||
|
||||
const CFRMessageProvider = {
|
||||
|
158
browser/components/newtab/lib/InfoBar.jsm
Normal file
158
browser/components/newtab/lib/InfoBar.jsm
Normal file
@ -0,0 +1,158 @@
|
||||
/* 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.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
RemoteL10n: "resource://activity-stream/lib/RemoteL10n.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
});
|
||||
|
||||
class InfoBarNotification {
|
||||
constructor(message, dispatch) {
|
||||
this._dispatch = dispatch;
|
||||
this.dispatchUserAction = this.dispatchUserAction.bind(this);
|
||||
this.buttonCallback = this.buttonCallback.bind(this);
|
||||
this.infobarCallback = this.infobarCallback.bind(this);
|
||||
this.message = message;
|
||||
this.notification = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the infobar notification and send an impression ping
|
||||
*
|
||||
* @param {object} browser Browser reference for the currently selected tab
|
||||
*/
|
||||
showNotification(browser) {
|
||||
let { content } = this.message;
|
||||
let { gBrowser } = browser.ownerGlobal;
|
||||
let doc = gBrowser.ownerDocument;
|
||||
let notificationContainer;
|
||||
if (content.type === "global") {
|
||||
notificationContainer = browser.ownerGlobal.gHighPriorityNotificationBox;
|
||||
} else {
|
||||
notificationContainer = gBrowser.getNotificationBox(browser);
|
||||
}
|
||||
|
||||
this.notification = notificationContainer.appendNotification(
|
||||
this.formatMessageConfig(doc, content.text),
|
||||
this.message.id,
|
||||
content.icon || "chrome://branding/content/icon64.png",
|
||||
notificationContainer.PRIORITY_INFO_MEDIUM,
|
||||
content.buttons.map(b => this.formatButtonConfig(b)),
|
||||
this.infobarCallback
|
||||
);
|
||||
|
||||
this.addImpression();
|
||||
}
|
||||
|
||||
formatMessageConfig(doc, content) {
|
||||
let docFragment = doc.createDocumentFragment();
|
||||
// notificationbox will only `appendChild` for documentFragments
|
||||
docFragment.appendChild(RemoteL10n.createElement(doc, "span", { content }));
|
||||
|
||||
return docFragment;
|
||||
}
|
||||
|
||||
formatButtonConfig(button) {
|
||||
let btnConfig = { callback: this.buttonCallback, ...button };
|
||||
// notificationbox will set correct data-l10n-id attributes if passed in
|
||||
// using the l10n-id key. Otherwise the `button.label` text is used.
|
||||
if (button.label.string_id) {
|
||||
btnConfig["l10n-id"] = button.label.string_id;
|
||||
}
|
||||
|
||||
return btnConfig;
|
||||
}
|
||||
|
||||
addImpression() {
|
||||
// Record an impression in ASRouter for frequency capping
|
||||
this._dispatch({ type: "IMPRESSION", data: this.message });
|
||||
// Send a user impression telemetry ping
|
||||
this.sendUserEventTelemetry("IMPRESSION");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when one of the infobar buttons is clicked
|
||||
*/
|
||||
buttonCallback(notificationBox, btnDescription, target) {
|
||||
this.dispatchUserAction(
|
||||
btnDescription.action,
|
||||
target.ownerGlobal.gBrowser.selectedBrowser
|
||||
);
|
||||
let isPrimary = target.classList.contains("primary");
|
||||
let eventName = isPrimary
|
||||
? "CLICK_PRIMARY_BUTTON"
|
||||
: "CLICK_SECONDARY_BUTTON";
|
||||
this.sendUserEventTelemetry(eventName);
|
||||
}
|
||||
|
||||
dispatchUserAction(action, selectedBrowser) {
|
||||
this._dispatch({ type: "USER_ACTION", data: action }, selectedBrowser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when interacting with the toolbar (but not through the buttons)
|
||||
*/
|
||||
infobarCallback(eventType) {
|
||||
if (eventType === "removed" || eventType === "disconnected") {
|
||||
this.notification = null;
|
||||
} else {
|
||||
this.sendUserEventTelemetry(eventType.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
sendUserEventTelemetry(event) {
|
||||
const ping = {
|
||||
message_id: this.message.id,
|
||||
event,
|
||||
};
|
||||
this._dispatch({
|
||||
type: "INFOBAR_TELEMETRY",
|
||||
data: { action: "infobar_user_event", ...ping },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const InfoBar = {
|
||||
maybeLoadCustomElement(win) {
|
||||
if (!win.customElements.get("remote-text")) {
|
||||
Services.scriptloader.loadSubScript(
|
||||
"resource://activity-stream/data/custom-elements/paragraph.js",
|
||||
win
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
maybeInsertFTL(win) {
|
||||
win.MozXULElement.insertFTLIfNeeded("browser/newtab/asrouter.ftl");
|
||||
win.MozXULElement.insertFTLIfNeeded(
|
||||
"browser/defaultBrowserNotification.ftl"
|
||||
);
|
||||
},
|
||||
|
||||
showInfoBarMessage(browser, message, dispatch) {
|
||||
const win = browser.ownerGlobal;
|
||||
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(win)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.maybeLoadCustomElement(win);
|
||||
this.maybeInsertFTL(win);
|
||||
|
||||
let notification = new InfoBarNotification(message, dispatch);
|
||||
notification.showNotification(browser);
|
||||
|
||||
return notification;
|
||||
},
|
||||
};
|
||||
|
||||
this.InfoBar = InfoBar;
|
||||
|
||||
const EXPORTED_SYMBOLS = ["InfoBar"];
|
@ -218,6 +218,7 @@ class _RemoteL10n {
|
||||
"browser/branding/brandings.ftl",
|
||||
"browser/branding/sync-brand.ftl",
|
||||
"branding/brand.ftl",
|
||||
"browser/defaultBrowserNotification.ftl",
|
||||
],
|
||||
false,
|
||||
Services.prefs.getBoolPref(USE_REMOTE_L10N_PREF, true)
|
||||
|
@ -604,6 +604,9 @@ this.TelemetryFeed = class TelemetryFeed {
|
||||
case "whats-new-panel_user_event":
|
||||
event = await this.applyWhatsNewPolicy(event);
|
||||
break;
|
||||
case "infobar_user_event":
|
||||
event = await this.applyInfoBarPolicy(event);
|
||||
break;
|
||||
case "moments_user_event":
|
||||
event = await this.applyMomentsPolicy(event);
|
||||
break;
|
||||
@ -652,6 +655,13 @@ this.TelemetryFeed = class TelemetryFeed {
|
||||
return { ping, pingType: "whats-new-panel" };
|
||||
}
|
||||
|
||||
async applyInfoBarPolicy(ping) {
|
||||
ping.client_id = await this.telemetryClientId;
|
||||
ping.browser_session_id = browserSessionId;
|
||||
delete ping.action;
|
||||
return { ping, pingType: "infobar" };
|
||||
}
|
||||
|
||||
/**
|
||||
* Per Bug 1484035, Moments metrics comply with following policies:
|
||||
* 1). In release, it collects impression_id, and treats bucket_id as message_id
|
||||
@ -945,6 +955,8 @@ this.TelemetryFeed = class TelemetryFeed {
|
||||
// Intentional fall-through
|
||||
case msg.DOORHANGER_TELEMETRY:
|
||||
// Intentional fall-through
|
||||
case msg.INFOBAR_TELEMETRY:
|
||||
// Intentional fall-through
|
||||
case at.AS_ROUTER_TELEMETRY_USER_EVENT:
|
||||
this.handleASRouterUserEvent(action);
|
||||
break;
|
||||
|
@ -43,6 +43,7 @@ skip-if = (os == "linux") # Test setup only implemented for OSX and Windows
|
||||
[browser_topsites_contextMenu_options.js]
|
||||
[browser_topsites_section.js]
|
||||
[browser_asrouter_cfr.js]
|
||||
[browser_asrouter_infobar.js]
|
||||
[browser_asrouter_bookmarkpanel.js]
|
||||
[browser_asrouter_toolbarbadge.js]
|
||||
[browser_asrouter_whatsnewpanel.js]
|
||||
|
@ -0,0 +1,85 @@
|
||||
const { InfoBar } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/InfoBar.jsm"
|
||||
);
|
||||
const { CFRMessageProvider } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/CFRMessageProvider.jsm"
|
||||
);
|
||||
const { ASRouter } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/ASRouter.jsm"
|
||||
);
|
||||
const { BrowserWindowTracker } = ChromeUtils.import(
|
||||
"resource:///modules/BrowserWindowTracker.jsm"
|
||||
);
|
||||
|
||||
add_task(async function show_and_send_telemetry() {
|
||||
let message = (await CFRMessageProvider.getMessages()).find(
|
||||
m => m.id === "INFOBAR_ACTION_86"
|
||||
);
|
||||
|
||||
Assert.ok(message.id, "Found the message");
|
||||
|
||||
let dispatchStub = sinon.stub();
|
||||
let infobar = InfoBar.showInfoBarMessage(
|
||||
BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser,
|
||||
message,
|
||||
dispatchStub
|
||||
);
|
||||
|
||||
Assert.equal(dispatchStub.callCount, 2, "Called twice with IMPRESSION");
|
||||
// This is the call to increment impressions for frequency capping
|
||||
Assert.equal(dispatchStub.firstCall.args[0].type, "IMPRESSION");
|
||||
Assert.equal(dispatchStub.firstCall.args[0].data.id, message.id);
|
||||
// This is the telemetry ping
|
||||
Assert.equal(dispatchStub.secondCall.args[0].data.event, "IMPRESSION");
|
||||
Assert.equal(dispatchStub.secondCall.args[0].data.message_id, message.id);
|
||||
|
||||
let primaryBtn = infobar.notification.querySelector(
|
||||
".notification-button.primary"
|
||||
);
|
||||
|
||||
Assert.ok(primaryBtn, "Has a primary button");
|
||||
primaryBtn.click();
|
||||
|
||||
Assert.equal(dispatchStub.callCount, 4, "Called again with CLICK + removed");
|
||||
Assert.equal(dispatchStub.thirdCall.args[0].type, "USER_ACTION");
|
||||
Assert.equal(
|
||||
dispatchStub.lastCall.args[0].data.event,
|
||||
"CLICK_PRIMARY_BUTTON"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function react_to_trigger() {
|
||||
let message = {
|
||||
...(await CFRMessageProvider.getMessages()).find(
|
||||
m => m.id === "INFOBAR_ACTION_86"
|
||||
),
|
||||
};
|
||||
message.targeting = "true";
|
||||
message.content.type = "tab";
|
||||
message.groups = [];
|
||||
message.provider = ASRouter.state.providers[0].id;
|
||||
message.content.message = "Infobar Mochitest";
|
||||
await ASRouter.setState({ messages: [message] });
|
||||
|
||||
let notificationStack = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
|
||||
Assert.ok(
|
||||
!notificationStack.currentNotification,
|
||||
"No notification to start with"
|
||||
);
|
||||
|
||||
await ASRouter.sendTriggerMessage({
|
||||
browser: BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser,
|
||||
id: "defaultBrowserCheck",
|
||||
});
|
||||
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => notificationStack.currentNotification,
|
||||
"Wait for notification to show"
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
notificationStack.currentNotification.getAttribute("value"),
|
||||
message.id,
|
||||
"Notification id should match"
|
||||
);
|
||||
});
|
@ -912,7 +912,7 @@ add_task(async function checkPatternMatches() {
|
||||
|
||||
add_task(async function checkPatternsValid() {
|
||||
const messages = (await CFRMessageProvider.getMessages()).filter(
|
||||
m => m.trigger.patterns
|
||||
m => m.trigger?.patterns
|
||||
);
|
||||
|
||||
for (const message of messages) {
|
||||
|
@ -14,8 +14,8 @@ describe("CFRMessageProvider", () => {
|
||||
beforeEach(async () => {
|
||||
messages = await CFRMessageProvider.getMessages();
|
||||
});
|
||||
it("should have a total of 13 messages", () => {
|
||||
assert.lengthOf(messages, 13);
|
||||
it("should have a total of 14 messages", () => {
|
||||
assert.lengthOf(messages, 14);
|
||||
});
|
||||
it("should have one message each for the three regular addons", () => {
|
||||
for (const id of REGULAR_IDS) {
|
||||
@ -29,21 +29,6 @@ describe("CFRMessageProvider", () => {
|
||||
assert.notInclude(cohort3.targeting, `providerCohorts.cfr`);
|
||||
}
|
||||
});
|
||||
it("should always have xpinstallEnabled as targeting if it is an addon", () => {
|
||||
for (const message of messages) {
|
||||
// Ensure that the CFR messages that are recommending an addon have this targeting.
|
||||
// In the future when we can do targeting based on category, this test will change.
|
||||
// See bug 1494778 and 1497653
|
||||
if (!message.content.layout) {
|
||||
assert.include(message.targeting, `(xpinstallEnabled == true)`);
|
||||
}
|
||||
}
|
||||
});
|
||||
it("should restrict all messages to `en` locale for now (PIN TAB is handled separately)", () => {
|
||||
for (const message of messages.filter(m => !m.content.layout)) {
|
||||
assert.include(message.targeting, `localeLanguageCode == "en"`);
|
||||
}
|
||||
});
|
||||
it("should restrict locale for PIN_TAB message", () => {
|
||||
const pinTabMessage = messages.find(m => m.id === "PIN_TAB");
|
||||
|
||||
|
@ -64,6 +64,7 @@ describe("RemoteL10n", () => {
|
||||
"browser/branding/brandings.ftl",
|
||||
"browser/branding/sync-brand.ftl",
|
||||
"branding/brand.ftl",
|
||||
"browser/defaultBrowserNotification.ftl",
|
||||
]);
|
||||
assert.isFalse(args[1]);
|
||||
assert.isFunction(args[2].generateBundles);
|
||||
@ -82,6 +83,7 @@ describe("RemoteL10n", () => {
|
||||
"browser/branding/brandings.ftl",
|
||||
"browser/branding/sync-brand.ftl",
|
||||
"branding/brand.ftl",
|
||||
"browser/defaultBrowserNotification.ftl",
|
||||
]);
|
||||
assert.isFalse(args[1]);
|
||||
assert.isEmpty(args[2]);
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { CFRMessageProvider } from "lib/CFRMessageProvider.jsm";
|
||||
import CFRDoorhangerSchema from "content-src/asrouter/templates/CFR/templates/ExtensionDoorhanger.schema.json";
|
||||
import CFRChicletSchema from "content-src/asrouter/templates/CFR/templates/CFRUrlbarChiclet.schema.json";
|
||||
import InfoBarSchema from "content-src/asrouter/templates/CFR/templates/InfoBar.schema.json";
|
||||
|
||||
const SCHEMAS = {
|
||||
cfr_urlbar_chiclet: CFRChicletSchema,
|
||||
cfr_doorhanger: CFRDoorhangerSchema,
|
||||
milestone_message: CFRDoorhangerSchema,
|
||||
infobar: InfoBarSchema,
|
||||
};
|
||||
|
||||
const DEFAULT_CONTENT = {
|
||||
|
@ -766,6 +766,14 @@ describe("TelemetryFeed", () => {
|
||||
assert.equal(pingType, "whats-new-panel");
|
||||
});
|
||||
});
|
||||
describe("#applyInfoBarPolicy", () => {
|
||||
it("should set client_id and set pingType", async () => {
|
||||
const { ping, pingType } = await instance.applyInfoBarPolicy({});
|
||||
|
||||
assert.propertyVal(ping, "client_id", FAKE_TELEMETRY_ID);
|
||||
assert.equal(pingType, "infobar");
|
||||
});
|
||||
});
|
||||
describe("#applyMomentsPolicy", () => {
|
||||
it("should use client_id and message_id in prerelease", async () => {
|
||||
globals.set("UpdateUtils", {
|
||||
|
@ -14,11 +14,17 @@ add_task(async function test_all_test_messages() {
|
||||
|
||||
for (let message of messagesWithButtons) {
|
||||
info(`Testing ${message.id}`);
|
||||
let { primary, secondary } = message.content.buttons;
|
||||
await SMATestUtils.validateAction(primary.action);
|
||||
for (let secondaryBtn of secondary) {
|
||||
if (secondaryBtn.action) {
|
||||
await SMATestUtils.validateAction(secondaryBtn.action);
|
||||
if (message.template === "infobar") {
|
||||
for (let button of message.content.buttons) {
|
||||
await SMATestUtils.validateAction(button.action);
|
||||
}
|
||||
} else {
|
||||
let { primary, secondary } = message.content.buttons;
|
||||
await SMATestUtils.validateAction(primary.action);
|
||||
for (let secondaryBtn of secondary) {
|
||||
if (secondaryBtn.action) {
|
||||
await SMATestUtils.validateAction(secondaryBtn.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,8 +158,35 @@
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"description": "Happens every time Firefox blocks the loading of a page script/asset/resource that matches the one of the tracking behaviours specifid through params. See https://searchfox.org/mozilla-central/rev/8ccea36c4fb09412609fb738c722830d7098602b/uriloader/base/nsIWebProgressListener.idl#336"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"enum": ["defaultBrowserCheck"]
|
||||
},
|
||||
"context": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": ["newtab"],
|
||||
"description": "When the source of the trigger is home/newtab"
|
||||
},
|
||||
"willShowDefaultPrompt": {
|
||||
"type": "boolean",
|
||||
"description": "When the source of the trigger is startup"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["id"],
|
||||
"description": "Happens when starting the browser or navigating to about:home/newtab"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,3 +108,14 @@ ANDing the various STATE_BLOCKED_* flags.
|
||||
let event: ContentBlockingEventFlag;
|
||||
let pageLoad = number;
|
||||
```
|
||||
|
||||
### `defaultBrowserCheck`
|
||||
|
||||
Happens at startup, when opening a newtab and when navigating to about:home.
|
||||
At startup it provides the result of running `DefaultBrowserCheck.willCheckDefaultBrowser` to follow existing behaviour if needed.
|
||||
On the newtab/homepage it reports the `source` as `newtab`.
|
||||
|
||||
```typescript
|
||||
let source = "newtab" | undefined;
|
||||
let willShowDefaultPrompt = boolean;
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user