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