Merge autoland to mozilla-central. a=merge
[gecko.git] / browser / actors / AboutPrivateBrowsingParent.sys.mjs
blob5c6757b8a0ed617b7897ea76bfd07cedb313a6e7
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 import { ASRouter } from "resource:///modules/asrouter/ASRouter.sys.mjs";
6 import { BrowserUtils } from "resource://gre/modules/BrowserUtils.sys.mjs";
7 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
9 const SHOWN_PREF = "browser.search.separatePrivateDefault.ui.banner.shown";
10 const lazy = {};
11 XPCOMUtils.defineLazyPreferenceGetter(
12   lazy,
13   "MAX_SEARCH_BANNER_SHOW_COUNT",
14   "browser.search.separatePrivateDefault.ui.banner.max",
15   0
18 XPCOMUtils.defineLazyPreferenceGetter(
19   lazy,
20   "isPrivateSearchUIEnabled",
21   "browser.search.separatePrivateDefault.ui.enabled",
22   false
25 ChromeUtils.defineESModuleGetters(lazy, {
26   SpecialMessageActions:
27     "resource://messaging-system/lib/SpecialMessageActions.sys.mjs",
28 });
30 // We only show the private search banner once per browser session.
31 let gSearchBannerShownThisSession;
33 export class AboutPrivateBrowsingParent extends JSWindowActorParent {
34   constructor() {
35     super();
36     Services.telemetry.setEventRecordingEnabled("aboutprivatebrowsing", true);
37   }
38   // Used by tests
39   static setShownThisSession(shown) {
40     gSearchBannerShownThisSession = shown;
41   }
43   receiveMessage(aMessage) {
44     let browser = this.browsingContext.top.embedderElement;
45     if (!browser) {
46       return undefined;
47     }
49     let win = browser.ownerGlobal;
51     switch (aMessage.name) {
52       case "OpenPrivateWindow": {
53         win.OpenBrowserWindow({ private: true });
54         break;
55       }
56       case "OpenSearchPreferences": {
57         win.openPreferences("search", { origin: "about-privatebrowsing" });
58         break;
59       }
60       case "SearchHandoff": {
61         let urlBar = win.gURLBar;
62         let searchEngine = Services.search.defaultPrivateEngine;
63         let isFirstChange = true;
65         if (!aMessage.data || !aMessage.data.text) {
66           urlBar.setHiddenFocus();
67         } else {
68           // Pass the provided text to the awesomebar
69           urlBar.handoff(aMessage.data.text, searchEngine);
70           isFirstChange = false;
71         }
73         let checkFirstChange = () => {
74           // Check if this is the first change since we hidden focused. If it is,
75           // remove hidden focus styles, prepend the search alias and hide the
76           // in-content search.
77           if (isFirstChange) {
78             isFirstChange = false;
79             urlBar.removeHiddenFocus(true);
80             urlBar.handoff("", searchEngine);
81             this.sendAsyncMessage("DisableSearch");
82             urlBar.removeEventListener("compositionstart", checkFirstChange);
83             urlBar.removeEventListener("paste", checkFirstChange);
84           }
85         };
87         let onKeydown = ev => {
88           // Check if the keydown will cause a value change.
89           if (ev.key.length === 1 && !ev.altKey && !ev.ctrlKey && !ev.metaKey) {
90             checkFirstChange();
91           }
92           // If the Esc button is pressed, we are done. Show in-content search and cleanup.
93           if (ev.key === "Escape") {
94             onDone();
95           }
96         };
98         let onDone = ev => {
99           // We are done. Show in-content search again and cleanup.
100           this.sendAsyncMessage("ShowSearch");
102           const forceSuppressFocusBorder = ev?.type === "mousedown";
103           urlBar.removeHiddenFocus(forceSuppressFocusBorder);
105           urlBar.removeEventListener("keydown", onKeydown);
106           urlBar.removeEventListener("mousedown", onDone);
107           urlBar.removeEventListener("blur", onDone);
108           urlBar.removeEventListener("compositionstart", checkFirstChange);
109           urlBar.removeEventListener("paste", checkFirstChange);
110         };
112         urlBar.addEventListener("keydown", onKeydown);
113         urlBar.addEventListener("mousedown", onDone);
114         urlBar.addEventListener("blur", onDone);
115         urlBar.addEventListener("compositionstart", checkFirstChange);
116         urlBar.addEventListener("paste", checkFirstChange);
117         break;
118       }
119       case "ShouldShowSearchBanner": {
120         // If this is a pre-loaded private browsing new tab, then we don't want
121         // to display the banner - it might never get displayed to the user
122         // and we won't know, or it might get displayed at the wrong time.
123         // This has the minor downside of not displaying the banner if
124         // you go into private browsing via opening a link, and then opening
125         // a new tab, we won't display the banner, for now, that's ok.
126         if (browser.getAttribute("preloadedState") === "preloaded") {
127           return null;
128         }
130         if (!lazy.isPrivateSearchUIEnabled || gSearchBannerShownThisSession) {
131           return null;
132         }
133         gSearchBannerShownThisSession = true;
134         const shownTimes = Services.prefs.getIntPref(SHOWN_PREF, 0);
135         if (shownTimes >= lazy.MAX_SEARCH_BANNER_SHOW_COUNT) {
136           return null;
137         }
138         Services.prefs.setIntPref(SHOWN_PREF, shownTimes + 1);
139         return new Promise(resolve => {
140           Services.search.getDefaultPrivate().then(engine => {
141             resolve(engine.name);
142           });
143         });
144       }
145       case "SearchBannerDismissed": {
146         Services.prefs.setIntPref(
147           SHOWN_PREF,
148           lazy.MAX_SEARCH_BANNER_SHOW_COUNT
149         );
150         break;
151       }
152       case "ShouldShowPromo": {
153         return BrowserUtils.shouldShowPromo(
154           BrowserUtils.PromoType[aMessage.data.type]
155         );
156       }
157       case "SpecialMessageActionDispatch": {
158         lazy.SpecialMessageActions.handleAction(aMessage.data, browser);
159         break;
160       }
161       case "IsPromoBlocked": {
162         return !ASRouter.isUnblockedMessage(aMessage.data);
163       }
164     }
166     return undefined;
167   }