diff --git a/browser/actors/AboutPrivateBrowsingChild.jsm b/browser/actors/AboutPrivateBrowsingChild.jsm index df9cdce760d6..31556636b853 100644 --- a/browser/actors/AboutPrivateBrowsingChild.jsm +++ b/browser/actors/AboutPrivateBrowsingChild.jsm @@ -46,10 +46,8 @@ class AboutPrivateBrowsingChild extends RemotePageChild { } } - PrivateBrowsingFeatureConfig(defaultValues) { - const config = NimbusFeatures.privatebrowsing.getAllVariables({ - defaultValues, - }); + PrivateBrowsingFeatureConfig() { + const config = NimbusFeatures.privatebrowsing.getAllVariables() || {}; NimbusFeatures.privatebrowsing.recordExposureEvent(); diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 0861efea600f..d6eef04b4f43 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1461,7 +1461,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\":false,\"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\",\"aboutwelcome\",\"infobar\",\"spotlight\",\"moments-page\"],\"updateCycleInMs\":3600000}"); +pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "{\"id\":\"messaging-experiments\",\"enabled\":true,\"type\":\"remote-experiments\",\"messageGroups\":[\"cfr\",\"aboutwelcome\",\"infobar\",\"spotlight\",\"moments-page\",\"pbNewtab\"],\"updateCycleInMs\":3600000}"); // ASRouter user prefs pref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", true); diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index f1219b4899c2..7f132a0a9203 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -718,7 +718,12 @@ let JSWINDOWACTORS = { DOMDocElementInserted: {}, }, }, - matches: ["about:home*", "about:newtab*", "about:welcome*"], + matches: [ + "about:home*", + "about:newtab*", + "about:welcome*", + "about:privatebrowsing", + ], remoteTypes: ["privilegedabout"], }, diff --git a/browser/components/extensions/test/browser/browser_ext_menus_incognito.js b/browser/components/extensions/test/browser/browser_ext_menus_incognito.js index 43edb4be44a8..00ddb33d69c2 100644 --- a/browser/components/extensions/test/browser/browser_ext_menus_incognito.js +++ b/browser/components/extensions/test/browser/browser_ext_menus_incognito.js @@ -118,7 +118,7 @@ add_task(async function test_no_show_hide_for_private_window() { }); // Open and close a menu on the private window. - let menu = await openContextMenu("body", privateWindow); + let menu = await openContextMenu("body div", privateWindow); // We should not see the "not_allowed" extension here. ok( !privateWindow.document.getElementById(extMenuId), diff --git a/browser/components/newtab/common/ActorConstants.jsm b/browser/components/newtab/common/ActorConstants.jsm index dc6f455badce..c8dcbc3a0b05 100644 --- a/browser/components/newtab/common/ActorConstants.jsm +++ b/browser/components/newtab/common/ActorConstants.jsm @@ -10,6 +10,8 @@ const MESSAGE_TYPE_LIST = [ "IMPRESSION", "TRIGGER", "NEWTAB_MESSAGE_REQUEST", + // PB is Private Browsing + "PBNEWTAB_MESSAGE_REQUEST", "DOORHANGER_TELEMETRY", "TOOLBAR_BADGE_TELEMETRY", "TOOLBAR_PANEL_TELEMETRY", diff --git a/browser/components/newtab/content-src/asrouter/templates/PBNewtab/NewtabPromoMessage.schema.json b/browser/components/newtab/content-src/asrouter/templates/PBNewtab/NewtabPromoMessage.schema.json new file mode 100644 index 000000000000..fbf746525de9 --- /dev/null +++ b/browser/components/newtab/content-src/asrouter/templates/PBNewtab/NewtabPromoMessage.schema.json @@ -0,0 +1,78 @@ +{ + "title": "PBNewtabPromoMessage", + "description": "Message shown on the private browsing newtab page.", + "version": "1.0.0", + "type": "object", + "properties": { + "infoEnabled": { + "type": "boolean", + "description": "Should we show the info section." + }, + "infoIcon": { + "type": "string", + "description": "Icon shown in the left side of the info section. Default is the private browsing icon." + }, + "infoTitle": { + "type": "string", + "description": "Is the title in the info section enabled." + }, + "infoTitleEnabled": { + "type": "boolean", + "description": "Is the title in the info section enabled." + }, + "infoBody": { + "type": "string", + "description": "Text content in the info section." + }, + "infoLinkText": { + "type": "string", + "description": "Text for the link in the info section." + }, + "infoLinkUrl": { + "type": "string", + "description": "URL for the info section link." + }, + "promoEnabled": { + "type": "boolean", + "description": "Should we show the promo section." + }, + "promoSectionStyle": { + "type": "string", + "description": "Sets the position of the promo section. Possible values are: top, below-search, bottom. Default bottom.", + "enum": ["top", "below-search", "bottom"] + }, + "promoTitle": { + "type": "string", + "description": "The text content of the promo section." + }, + "promoTitleEnabled": { + "type": "boolean", + "description": "Should we show text content in the promo section." + }, + "promoLinkText": { + "type": "string", + "description": "The text of the link in the promo box." + }, + "promoHeader": { + "type": "string", + "description": "The title of the promo section." + }, + "promoLinkUrl": { + "type": "string", + "description": "URL for link in the promo box." + }, + "promoLinkType": { + "type": "string", + "description": "Type of promo link type. Possible values: link, button. Default is link.", + "enum": ["link", "button"] + }, + "promoImageLarge": { + "type": "string", + "description": "URL for image used on the left side of the promo box, larger, showcases some feature. Default off." + }, + "promoImageSmall": { + "type": "string", + "description": "URL for image used on the right side of the promo box, smaller, usually a logo. Default off." + } + } +} diff --git a/browser/components/newtab/data/content/activity-stream.bundle.js b/browser/components/newtab/data/content/activity-stream.bundle.js index 418a8a342860..44ba419b8d1b 100644 --- a/browser/components/newtab/data/content/activity-stream.bundle.js +++ b/browser/components/newtab/data/content/activity-stream.bundle.js @@ -2363,7 +2363,8 @@ __webpack_require__.r(__webpack_exports__); * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const MESSAGE_TYPE_LIST = ["BLOCK_MESSAGE_BY_ID", "USER_ACTION", "IMPRESSION", "TRIGGER", "NEWTAB_MESSAGE_REQUEST", "DOORHANGER_TELEMETRY", "TOOLBAR_BADGE_TELEMETRY", "TOOLBAR_PANEL_TELEMETRY", "MOMENTS_PAGE_TELEMETRY", "INFOBAR_TELEMETRY", "SPOTLIGHT_TELEMETRY", "AS_ROUTER_TELEMETRY_USER_EVENT", // Admin types +const MESSAGE_TYPE_LIST = ["BLOCK_MESSAGE_BY_ID", "USER_ACTION", "IMPRESSION", "TRIGGER", "NEWTAB_MESSAGE_REQUEST", // PB is Private Browsing +"PBNEWTAB_MESSAGE_REQUEST", "DOORHANGER_TELEMETRY", "TOOLBAR_BADGE_TELEMETRY", "TOOLBAR_PANEL_TELEMETRY", "MOMENTS_PAGE_TELEMETRY", "INFOBAR_TELEMETRY", "SPOTLIGHT_TELEMETRY", "AS_ROUTER_TELEMETRY_USER_EVENT", // Admin types "ADMIN_CONNECT_STATE", "UNBLOCK_MESSAGE_BY_ID", "UNBLOCK_ALL", "BLOCK_BUNDLE", "UNBLOCK_BUNDLE", "DISABLE_PROVIDER", "ENABLE_PROVIDER", "EVALUATE_JEXL_EXPRESSION", "EXPIRE_QUERY_CACHE", "FORCE_ATTRIBUTION", "FORCE_WHATSNEW_PANEL", "CLOSE_WHATSNEW_PANEL", "OVERRIDE_MESSAGE", "MODIFY_MESSAGE_JSON", "RESET_PROVIDER_PREF", "SET_PROVIDER_USER_PREF", "RESET_GROUPS_STATE"]; const MESSAGE_TYPE_HASH = MESSAGE_TYPE_LIST.reduce((hash, value) => { hash[value] = value; diff --git a/browser/components/newtab/lib/ASRouter.jsm b/browser/components/newtab/lib/ASRouter.jsm index 5a3d945a9fb2..f7ee2b82e58d 100644 --- a/browser/components/newtab/lib/ASRouter.jsm +++ b/browser/components/newtab/lib/ASRouter.jsm @@ -1582,6 +1582,30 @@ class _ASRouter { return this.loadMessagesFromAllProviders(); } + async sendPBNewTabMessage({ tabId }) { + let message = null; + + await this.loadMessagesFromAllProviders(); + + const telemetryObject = { tabId }; + TelemetryStopwatch.start("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject); + message = await this.handleMessageRequest({ template: "pb_newtab" }); + TelemetryStopwatch.finish("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject); + + // Format urls if any are defined + ["infoLinkUrl", "promoLinkUrl"].forEach(key => { + if (message?.content?.[key]) { + message.content[key] = Services.urlFormatter.formatURL( + message.content[key] + ); + } + }); + + NimbusFeatures.pbNewtab.recordExposureEvent({ once: true }); + + return { message }; + } + async sendNewTabMessage({ endpoint, tabId, browser }) { let message; @@ -1662,6 +1686,7 @@ class _ASRouter { spotlight: "spotlight", infobar: "infobar", update_action: "moments-page", + pb_newtab: "pbNewtab", }; let feature = featureMap[nonReachMessages[0].template]; if (feature) { diff --git a/browser/components/newtab/lib/ASRouterParentProcessMessageHandler.jsm b/browser/components/newtab/lib/ASRouterParentProcessMessageHandler.jsm index 65db12f5490d..5e0e62c94452 100644 --- a/browser/components/newtab/lib/ASRouterParentProcessMessageHandler.jsm +++ b/browser/components/newtab/lib/ASRouterParentProcessMessageHandler.jsm @@ -75,6 +75,13 @@ class ASRouterParentProcessMessageHandler { browser, }); } + case msg.PBNEWTAB_MESSAGE_REQUEST: { + return this._router.sendPBNewTabMessage({ + ...data, + tabId, + browser, + }); + } case msg.NEWTAB_MESSAGE_REQUEST: { return this._router.sendNewTabMessage({ ...data, diff --git a/browser/components/newtab/lib/OnboardingMessageProvider.jsm b/browser/components/newtab/lib/OnboardingMessageProvider.jsm index 8202fd50c984..034eba189c09 100644 --- a/browser/components/newtab/lib/OnboardingMessageProvider.jsm +++ b/browser/components/newtab/lib/OnboardingMessageProvider.jsm @@ -37,6 +37,20 @@ const ONBOARDING_MESSAGES = () => [ }, trigger: { id: "protectionsPanelOpen" }, }, + { + id: "PB_NEWTAB_INFO_SECTION", + template: "pb_newtab", + content: { + promoEnabled: false, + infoEnabled: true, + infoIcon: "", + infoTitle: "", + infoBody: "fluent:about-private-browsing-info-description-private-window", + infoLinkText: "fluent:about-private-browsing-learn-more-link", + infoTitleEnabled: false, + }, + targeting: "true", + }, ]; const OnboardingMessageProvider = { diff --git a/browser/components/newtab/lib/PanelTestProvider.jsm b/browser/components/newtab/lib/PanelTestProvider.jsm index cf50f1dcd38c..43a278747e65 100644 --- a/browser/components/newtab/lib/PanelTestProvider.jsm +++ b/browser/components/newtab/lib/PanelTestProvider.jsm @@ -311,6 +311,28 @@ const MESSAGES = () => [ frequency: { lifetime: 3 }, trigger: { id: "defaultBrowserCheck" }, }, + { + id: "PB_NEWTAB_VPN_PROMO", + template: "pb_newtab", + content: { + promoEnabled: true, + infoEnabled: true, + infoIcon: "", + infoTitle: "", + infoBody: "fluent:about-private-browsing-info-description-private-window", + infoLinkText: "fluent:about-private-browsing-learn-more-link", + infoTitleEnabled: false, + promoLinkType: "button", + promoLinkText: "fluent:about-private-browsing-prominent-cta", + promoSectionStyle: "below-search", + promoHeader: "fluent:about-private-browsing-get-privacy", + promoTitle: "fluent:about-private-browsing-hide-activity-1", + promoTitleEnabled: true, + promoImageLarge: "chrome://browser/content/assets/moz-vpn.svg", + }, + targeting: "region != 'CN' && !hasActiveEnterprisePolicies", + frequency: { lifetime: 3 }, + }, ]; const PanelTestProvider = { diff --git a/browser/components/newtab/test/unit/asrouter/CFRMessageProvider.test.js b/browser/components/newtab/test/unit/asrouter/CFRMessageProvider.test.js index c1e2213f1f81..542f5de2f29c 100644 --- a/browser/components/newtab/test/unit/asrouter/CFRMessageProvider.test.js +++ b/browser/components/newtab/test/unit/asrouter/CFRMessageProvider.test.js @@ -14,7 +14,7 @@ describe("CFRMessageProvider", () => { beforeEach(async () => { messages = await CFRMessageProvider.getMessages(); }); - it("should have a total of 10 messages", () => { + it("should have a total of 11 messages", () => { assert.lengthOf(messages, 11); }); it("should have one message each for the three regular addons", () => { diff --git a/browser/components/newtab/test/unit/asrouter/PanelTestProvider.test.js b/browser/components/newtab/test/unit/asrouter/PanelTestProvider.test.js index 24a3f9a15275..345ad5a0ecd7 100644 --- a/browser/components/newtab/test/unit/asrouter/PanelTestProvider.test.js +++ b/browser/components/newtab/test/unit/asrouter/PanelTestProvider.test.js @@ -2,16 +2,17 @@ import { PanelTestProvider } from "lib/PanelTestProvider.jsm"; import update_schema from "content-src/asrouter/templates/OnboardingMessage/UpdateAction.schema.json"; import whats_new_schema from "content-src/asrouter/templates/OnboardingMessage/WhatsNewMessage.schema.json"; import spotlight_schema from "content-src/asrouter/templates/OnboardingMessage/Spotlight.schema.json"; +import PBNewtabSchema from "content-src/asrouter/templates/PBNewtab/NewtabPromoMessage.schema.json"; describe("PanelTestProvider", () => { let messages; beforeEach(async () => { messages = await PanelTestProvider.getMessages(); }); - it("should have a message", () => { + it("should have 12 messages", () => { // Careful: when changing this number make sure that new messages also go // through schema verifications. - assert.lengthOf(messages, 11); + assert.lengthOf(messages, 12); }); it("should be a valid message", () => { const updateMessages = messages.filter( @@ -31,7 +32,7 @@ describe("PanelTestProvider", () => { assert.property(message, "order"); } }); - it("should be a valid message", () => { + it("should be a valid spotlight message", () => { const spotlightMessages = messages.filter( ({ template }) => template === "spotlight" ); @@ -39,4 +40,11 @@ describe("PanelTestProvider", () => { assert.jsonSchema(message, spotlight_schema); } }); + it("should be a valid pb newtab message", () => { + const pbNewtabMessages = messages.filter( + ({ template }) => template === "pb_newtab" + ); + assert.lengthOf(pbNewtabMessages, 1); + pbNewtabMessages.forEach(m => assert.jsonSchema(m, PBNewtabSchema)); + }); }); diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html index 10ee1d8f95b6..7292178d6ef8 100644 --- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html +++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html @@ -60,7 +60,7 @@ -
+