Bug 1616700 - Part 3 - Update the placeholder string on the handoff input to read "Search with {engine} or enter address" r=fluent-reviewers,Standard8
authorHarry Twyford <htwyford@mozilla.com>
Tue, 23 Mar 2021 22:56:54 +0000
changeset 572800 3aba8daf43c29f33ccdd380f6c9a9f3bf60df8b1
parent 572799 69900b283aa4250bc867cfb0ea03633244f56880
child 572801 90ff1773203a7bd476f8587e6f818f120c7c882a
push id139334
push userhtwyford@mozilla.com
push dateTue, 23 Mar 2021 23:44:25 +0000
treeherderautoland@3aba8daf43c2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfluent-reviewers, Standard8
bugs1616700
milestone89.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1616700 - Part 3 - Update the placeholder string on the handoff input to read "Search with {engine} or enter address" r=fluent-reviewers,Standard8 Differential Revision: https://phabricator.services.mozilla.com/D108266
browser/actors/AboutPrivateBrowsingParent.jsm
browser/components/newtab/content-src/components/Search/Search.jsx
browser/components/newtab/data/content/activity-stream.bundle.js
browser/components/newtab/lib/PrefsFeed.jsm
browser/components/privatebrowsing/content/aboutPrivateBrowsing.html
browser/components/privatebrowsing/content/aboutPrivateBrowsing.js
browser/components/search/content/contentSearchHandoffUI.js
browser/components/search/test/browser/browser_contentSearchUI_default.js
browser/locales/en-US/browser/aboutPrivateBrowsing.ftl
browser/locales/en-US/browser/newtab/newtab.ftl
toolkit/modules/RemotePageAccessManager.jsm
--- a/browser/actors/AboutPrivateBrowsingParent.jsm
+++ b/browser/actors/AboutPrivateBrowsingParent.jsm
@@ -107,16 +107,23 @@ class AboutPrivateBrowsingParent extends
 
         urlBar.addEventListener("keydown", onKeydown);
         urlBar.addEventListener("mousedown", onDone);
         urlBar.addEventListener("blur", onDone);
         urlBar.addEventListener("compositionstart", checkFirstChange);
         urlBar.addEventListener("paste", checkFirstChange);
         break;
       }
+      case "ShouldShowSearch": {
+        let engineName = Services.prefs.getStringPref(
+          "browser.urlbar.placeholderName.private",
+          ""
+        );
+        return engineName;
+      }
       case "ShouldShowSearchBanner": {
         // If this is a pre-loaded private browsing new tab, then we don't want
         // to display the banner - it might never get displayed to the user
         // and we won't know, or it might get displayed at the wrong time.
         // This has the minor downside of not displaying the banner if
         // you go into private browsing via opening a link, and then opening
         // a new tab, we won't display the banner, for now, that's ok.
         if (browser.getAttribute("preloadedState") === "preloaded") {
--- a/browser/components/newtab/content-src/components/Search/Search.jsx
+++ b/browser/components/newtab/content-src/components/Search/Search.jsx
@@ -101,22 +101,51 @@ export class _Search extends React.PureC
     } else {
       window.gContentSearchController = null;
       removeEventListener("ContentSearchClient", this);
     }
   }
 
   onInputMountHandoff(input) {
     if (input) {
-      // The handoff UI controller helps usset the search icon and reacts to
+      // The handoff UI controller helps us set the search icon and reacts to
       // changes to default engine to keep everything in sync.
       this._handoffSearchController = new ContentSearchHandoffUIController();
     }
   }
 
+  getDefaultEngineName() {
+    // _handoffSearchController will manage engine names once it is initialized.
+    return this.props.Prefs.values["urlbar.placeholderName"];
+  }
+
+  getHandoffInputL10nAttributes() {
+    let defaultEngineName = this.getDefaultEngineName();
+    return defaultEngineName
+      ? {
+          "data-l10n-id": "newtab-search-box-handoff-input",
+          "data-l10n-args": `{"engine": "${defaultEngineName}"}`,
+        }
+      : {
+          "data-l10n-id": "newtab-search-box-handoff-input-no-engine",
+        };
+  }
+
+  getHandoffTextL10nAttributes() {
+    let defaultEngineName = this.getDefaultEngineName();
+    return defaultEngineName
+      ? {
+          "data-l10n-id": "newtab-search-box-handoff-text",
+          "data-l10n-args": `{"engine": "${defaultEngineName}"}`,
+        }
+      : {
+          "data-l10n-id": "newtab-search-box-handoff-text-no-engine",
+        };
+  }
+
   onSearchHandoffButtonMount(button) {
     // Keep a reference to the button for use during "paste" event handling.
     this._searchHandoffButton = button;
   }
 
   /*
    * Do not change the ID on the input field, as legacy newtab code
    * specifically looks for the id 'newtab-search-text' on input fields
@@ -162,32 +191,24 @@ export class _Search extends React.PureC
               onClick={this.onSearchClick}
             />
           </div>
         )}
         {this.props.handoffEnabled && (
           <div className="search-inner-wrapper">
             <button
               className="search-handoff-button"
-              data-l10n-id={
-                isNewNewtabExperienceEnabled
-                  ? "newtab-search-box-input"
-                  : "newtab-search-box-search-the-web-input"
-              }
+              {...this.getHandoffInputL10nAttributes()}
               ref={this.onSearchHandoffButtonMount}
               onClick={this.onSearchHandoffClick}
               tabIndex="-1"
             >
               <div
                 className="fake-textbox"
-                data-l10n-id={
-                  isNewNewtabExperienceEnabled
-                    ? "newtab-search-box-text"
-                    : "newtab-search-box-search-the-web-text"
-                }
+                {...this.getHandoffTextL10nAttributes()}
               />
               <input
                 type="search"
                 className="fake-editable"
                 tabIndex="-1"
                 aria-hidden="true"
                 onDrop={this.onSearchHandoffDrop}
                 onPaste={this.onSearchHandoffPaste}
--- a/browser/components/newtab/data/content/activity-stream.bundle.js
+++ b/browser/components/newtab/data/content/activity-stream.bundle.js
@@ -10426,16 +10426,18 @@ const TopSites = Object(react_redux__WEB
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
 /* 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/. */
 
 /* globals ContentSearchUIController, ContentSearchHandoffUIController */
 
 
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
+
 
 
 
 
 class _Search extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComponent {
   constructor(props) {
     super(props);
     this.onSearchClick = this.onSearchClick.bind(this);
@@ -10530,22 +10532,47 @@ class _Search extends react__WEBPACK_IMP
     } else {
       window.gContentSearchController = null;
       removeEventListener("ContentSearchClient", this);
     }
   }
 
   onInputMountHandoff(input) {
     if (input) {
-      // The handoff UI controller helps usset the search icon and reacts to
+      // The handoff UI controller helps us set the search icon and reacts to
       // changes to default engine to keep everything in sync.
       this._handoffSearchController = new ContentSearchHandoffUIController();
     }
   }
 
+  getDefaultEngineName() {
+    // _handoffSearchController will manage engine names once it is initialized.
+    return this.props.Prefs.values["urlbar.placeholderName"];
+  }
+
+  getHandoffInputL10nAttributes() {
+    let defaultEngineName = this.getDefaultEngineName();
+    return defaultEngineName ? {
+      "data-l10n-id": "newtab-search-box-handoff-input",
+      "data-l10n-args": `{"engine": "${defaultEngineName}"}`
+    } : {
+      "data-l10n-id": "newtab-search-box-handoff-input-no-engine"
+    };
+  }
+
+  getHandoffTextL10nAttributes() {
+    let defaultEngineName = this.getDefaultEngineName();
+    return defaultEngineName ? {
+      "data-l10n-id": "newtab-search-box-handoff-text",
+      "data-l10n-args": `{"engine": "${defaultEngineName}"}`
+    } : {
+      "data-l10n-id": "newtab-search-box-handoff-text-no-engine"
+    };
+  }
+
   onSearchHandoffButtonMount(button) {
     // Keep a reference to the button for use during "paste" event handling.
     this._searchHandoffButton = button;
   }
   /*
    * Do not change the ID on the input field, as legacy newtab code
    * specifically looks for the id 'newtab-search-text' on input fields
    * in order to execute searches in various tests
@@ -10573,26 +10600,25 @@ class _Search extends react__WEBPACK_IMP
       type: "search"
     }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
       id: "searchSubmit",
       className: "search-button",
       "data-l10n-id": "newtab-search-box-search-button",
       onClick: this.onSearchClick
     })), this.props.handoffEnabled && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
       className: "search-inner-wrapper"
-    }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
-      className: "search-handoff-button",
-      "data-l10n-id": isNewNewtabExperienceEnabled ? "newtab-search-box-input" : "newtab-search-box-search-the-web-input",
+    }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", _extends({
+      className: "search-handoff-button"
+    }, this.getHandoffInputL10nAttributes(), {
       ref: this.onSearchHandoffButtonMount,
       onClick: this.onSearchHandoffClick,
       tabIndex: "-1"
-    }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
-      className: "fake-textbox",
-      "data-l10n-id": isNewNewtabExperienceEnabled ? "newtab-search-box-text" : "newtab-search-box-search-the-web-text"
-    }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+    }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", _extends({
+      className: "fake-textbox"
+    }, this.getHandoffTextL10nAttributes())), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
       type: "search",
       className: "fake-editable",
       tabIndex: "-1",
       "aria-hidden": "true",
       onDrop: this.onSearchHandoffDrop,
       onPaste: this.onSearchHandoffPaste,
       ref: this.onInputMountHandoff
     }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
--- a/browser/components/newtab/lib/PrefsFeed.jsm
+++ b/browser/components/newtab/lib/PrefsFeed.jsm
@@ -130,41 +130,52 @@ this.PrefsFeed = class PrefsFeed {
 
     // Get the firefox update channel with values as default, nightly, beta or release
     values.appUpdateChannel = Services.prefs.getStringPref(
       "app.update.channel",
       ""
     );
 
     // Read the pref for search shortcuts top sites experiment from firefox.js and store it
-    // in our interal list of prefs to watch
+    // in our internal list of prefs to watch
     let searchTopSiteExperimentPrefValue = Services.prefs.getBoolPref(
       "browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts"
     );
     values[
       "improvesearch.topSiteSearchShortcuts"
     ] = searchTopSiteExperimentPrefValue;
     this._prefMap.set("improvesearch.topSiteSearchShortcuts", {
       value: searchTopSiteExperimentPrefValue,
     });
 
     values.mayHaveSponsoredTopSites = Services.prefs.getBoolPref(
       "browser.topsites.useRemoteSetting"
     );
 
     // Read the pref for search hand-off from firefox.js and store it
-    // in our interal list of prefs to watch
+    // in our internal list of prefs to watch
     let handoffToAwesomebarPrefValue = Services.prefs.getBoolPref(
       "browser.newtabpage.activity-stream.improvesearch.handoffToAwesomebar"
     );
     values["improvesearch.handoffToAwesomebar"] = handoffToAwesomebarPrefValue;
     this._prefMap.set("improvesearch.handoffToAwesomebar", {
       value: handoffToAwesomebarPrefValue,
     });
 
+    // Read the pref for the cached default engine name from firefox.js and
+    // store it in our internal list of prefs to watch
+    let placeholderPrefValue = Services.prefs.getStringPref(
+      "browser.urlbar.placeholderName",
+      ""
+    );
+    values["urlbar.placeholderName"] = placeholderPrefValue;
+    this._prefMap.set("urlbar.placeholderName", {
+      value: placeholderPrefValue,
+    });
+
     // Add experiment values and default values
     values.featureConfig = aboutNewTabFeature.getValue() || {};
     this._setBoolPref(values, "logowordmark.alwaysVisible", false);
     this._setBoolPref(values, "feeds.section.topstories", false);
     this._setBoolPref(values, "discoverystream.enabled", false);
     this._setBoolPref(values, "discoverystream.isCollectionDismissible", false);
     this._setBoolPref(values, "discoverystream.hardcoded-basic-layout", false);
     this._setBoolPref(values, "discoverystream.recs.personalized", false);
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html
@@ -40,18 +40,18 @@
       </div>
     </div>
     <div class="showPrivate showSearch container">
       <div class="logo-and-wordmark">
         <div class="logo"></div>
         <div class="wordmark"></div>
       </div>
       <div class="search-inner-wrapper">
-        <button id="search-handoff-button" class="search-handoff-button" tabindex="-1" data-l10n-id="about-private-browsing">
-          <div class="fake-textbox" data-l10n-id="about-private-browsing-search-placeholder"></div>
+        <button id="search-handoff-button" class="search-handoff-button" tabindex="-1">
+          <div class="fake-textbox"></div>
           <input id="fake-editable" class="fake-editable" tabindex="-1" aria-hidden="true" />
           <div class="fake-caret"></div>
         </button>
       </div>
       <div class="info">
         <h1 data-l10n-id="about-private-browsing-info-title"></h1>
         <p data-l10n-id="about-private-browsing-info-description"></p>
         <a id="private-browsing-myths" data-l10n-id="about-private-browsing-info-myths"></a>
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js
@@ -86,16 +86,41 @@ document.addEventListener("DOMContentLoa
       hideSearchBanner();
     }
   };
   openSearchOptions.addEventListener("click", openSearchOptionsEvtHandler);
   openSearchOptions.addEventListener("keypress", openSearchOptionsEvtHandler);
 
   // Setup the search hand-off box.
   let btn = document.getElementById("search-handoff-button");
+  RPMSendQuery("ShouldShowSearch", {}).then(engineName => {
+    let input = document.querySelector(".fake-textbox");
+    if (engineName) {
+      document.l10n.setAttributes(btn, "about-private-browsing-handoff", {
+        engine: engineName,
+      });
+      document.l10n.setAttributes(
+        input,
+        "about-private-browsing-handoff-text",
+        {
+          engine: engineName,
+        }
+      );
+    } else {
+      document.l10n.setAttributes(
+        btn,
+        "about-private-browsing-handoff-no-engine"
+      );
+      document.l10n.setAttributes(
+        input,
+        "about-private-browsing-handoff-text-no-engine"
+      );
+    }
+  });
+
   let editable = document.getElementById("fake-editable");
   let DISABLE_SEARCH_TOPIC = "DisableSearch";
   let SHOW_SEARCH_TOPIC = "ShowSearch";
   let SEARCH_HANDOFF_TOPIC = "SearchHandoff";
 
   function showSearch() {
     btn.classList.remove("focused");
     btn.classList.remove("disabled");
@@ -131,11 +156,11 @@ document.addEventListener("DOMContentLoa
       handoffSearch(text);
     }
   });
   editable.addEventListener("paste", function(ev) {
     ev.preventDefault();
     handoffSearch(ev.clipboardData.getData("Text"));
   });
 
-  // Load contentSearchUI so it sets the search engine icon for us.
+  // Load contentSearchUI so it sets the search engine icon and name for us.
   new window.ContentSearchHandoffUIController();
 });
--- a/browser/components/search/content/contentSearchHandoffUI.js
+++ b/browser/components/search/content/contentSearchHandoffUI.js
@@ -15,34 +15,39 @@ function ContentSearchHandoffUIControlle
 ContentSearchHandoffUIController.prototype = {
   handleEvent(event) {
     let methodName = "_onMsg" + event.detail.type;
     if (methodName in this) {
       this[methodName](event.detail.data);
     }
   },
 
+  get defaultEngine() {
+    return this._defaultEngine;
+  },
+
   _onMsgEngine({ isPrivateWindow, engine }) {
     this._isPrivateWindow = isPrivateWindow;
-    this._updateEngineIcon(engine);
+    this._updateEngine(engine);
   },
 
   _onMsgCurrentEngine(engine) {
     if (!this._isPrivateWindow) {
-      this._updateEngineIcon(engine);
+      this._updateEngine(engine);
     }
   },
 
   _onMsgCurrentPrivateEngine(engine) {
     if (this._isPrivateWindow) {
-      this._updateEngineIcon(engine);
+      this._updateEngine(engine);
     }
   },
 
-  _updateEngineIcon(engine) {
+  _updateEngine(engine) {
+    this._defaultEngine = engine;
     if (this._engineIcon) {
       URL.revokeObjectURL(this._engineIcon);
     }
 
     // We only show the engines icon for app provided engines, otherwise show
     // a default. xref https://bugzilla.mozilla.org/show_bug.cgi?id=1449338#c19
     if (!engine.isAppProvided) {
       this._engineIcon = "chrome://global/skin/icons/search-glass.svg";
@@ -51,16 +56,52 @@ ContentSearchHandoffUIController.prototy
     } else {
       this._engineIcon = "chrome://global/skin/icons/defaultFavicon.svg";
     }
 
     document.body.style.setProperty(
       "--newtab-search-icon",
       "url(" + this._engineIcon + ")"
     );
+
+    let fakeButton = document.querySelector(".search-handoff-button");
+    let fakeInput = document.querySelector(".fake-textbox");
+    if (!engine.isAppProvided) {
+      document.l10n.setAttributes(
+        fakeButton,
+        this._isPrivateWindow
+          ? "about-private-browsing-handoff-no-engine"
+          : "newtab-search-box-handoff-input-no-engine"
+      );
+      document.l10n.setAttributes(
+        fakeInput,
+        this._isPrivateWindow
+          ? "about-private-browsing-handoff-text-no-engine"
+          : "newtab-search-box-handoff-text-no-engine"
+      );
+    } else {
+      document.l10n.setAttributes(
+        fakeButton,
+        this._isPrivateWindow
+          ? "about-private-browsing-handoff"
+          : "newtab-search-box-handoff-input",
+        {
+          engine: engine.name,
+        }
+      );
+      document.l10n.setAttributes(
+        fakeInput,
+        this._isPrivateWindow
+          ? "about-private-browsing-handoff-text"
+          : "newtab-search-box-handoff-text",
+        {
+          engine: engine.name,
+        }
+      );
+    }
   },
 
   // If the favicon is an array buffer, convert it into a Blob URI.
   // Otherwise just return the plain URI.
   _getFaviconURIFromIconData(data) {
     if (typeof data === "string") {
       return data;
     }
--- a/browser/components/search/test/browser/browser_contentSearchUI_default.js
+++ b/browser/components/search/test/browser/browser_contentSearchUI_default.js
@@ -22,18 +22,16 @@ add_task(async function setup() {
 
   addedEngine = await Services.search.getEngineByName(TEST_ENGINE_NAME);
 
   registerCleanupFunction(async () => {
     await Services.search.setDefault(defaultEngine);
   });
 });
 
-// async function runAboutNewTabTest(expectedIcon)
-
 async function ensureIcon(tab, expectedIcon) {
   await SpecialPowers.spawn(tab.linkedBrowser, [expectedIcon], async function(
     icon
   ) {
     await ContentTaskUtils.waitForCondition(() => !content.document.hidden);
 
     let computedStyle = content.window.getComputedStyle(content.document.body);
     await ContentTaskUtils.waitForCondition(
@@ -44,67 +42,105 @@ async function ensureIcon(tab, expectedI
     Assert.equal(
       computedStyle.getPropertyValue("--newtab-search-icon"),
       `url(${icon})`,
       "Should have the expected icon"
     );
   });
 }
 
-async function runNewTabTest() {
+async function ensurePlaceholder(tab, expectedId, expectedEngine) {
+  await SpecialPowers.spawn(
+    tab.linkedBrowser,
+    [expectedId, expectedEngine],
+    async function(id, engine) {
+      await ContentTaskUtils.waitForCondition(() => !content.document.hidden);
+
+      await ContentTaskUtils.waitForCondition(
+        () => content.document.querySelector(".search-handoff-button"),
+        "l10n ID not set."
+      );
+      let buttonNode = content.document.querySelector(".search-handoff-button");
+      let expectedAttributes = { id, args: engine ? { engine } : null };
+      Assert.deepEqual(
+        content.document.l10n.getAttributes(buttonNode),
+        expectedAttributes,
+        "Expected updated l10n ID and args."
+      );
+    }
+  );
+}
+
+async function runNewTabTest(isHandoff) {
   let tab = await BrowserTestUtils.openNewForegroundTab({
     url: "about:newtab",
     gBrowser,
     waitForLoad: false,
   });
 
   let engineIcon = defaultEngine.getIconURLBySize(16, 16);
 
   await ensureIcon(tab, engineIcon);
+  if (isHandoff) {
+    await ensurePlaceholder(
+      tab,
+      "newtab-search-box-handoff-input",
+      Services.search.defaultEngine.name
+    );
+  }
 
   await Services.search.setDefault(addedEngine);
 
   // We only show the engine's own icon for app provided engines, otherwise show
   // a default. xref https://bugzilla.mozilla.org/show_bug.cgi?id=1449338#c19
   await ensureIcon(tab, "chrome://global/skin/icons/search-glass.svg");
+  if (isHandoff) {
+    await ensurePlaceholder(tab, "newtab-search-box-handoff-input-no-engine");
+  }
 
   await Services.search.setDefault(defaultEngine);
 
   BrowserTestUtils.removeTab(tab);
 }
 
-add_task(async function test_content_search_icon() {
+add_task(async function test_content_search_attributes() {
   SpecialPowers.pushPrefEnv({
     set: [[HANDOFF_PREF, true]],
   });
 
-  await runNewTabTest();
+  await runNewTabTest(true);
 });
 
-add_task(async function test_content_search_icon_no_handoff() {
+add_task(async function test_content_search_attributes_no_handoff() {
   SpecialPowers.pushPrefEnv({
     set: [[HANDOFF_PREF, false]],
   });
 
-  await runNewTabTest();
+  await runNewTabTest(false);
 });
 
-add_task(async function test_content_search_icon_in_private_window() {
+add_task(async function test_content_search_attributes_in_private_window() {
   let win = await BrowserTestUtils.openNewBrowserWindow({
     private: true,
     waitForTabURL: "about:privatebrowsing",
   });
   let tab = win.gBrowser.selectedTab;
 
   let engineIcon = defaultEngine.getIconURLBySize(16, 16);
 
   await ensureIcon(tab, engineIcon);
+  await ensurePlaceholder(
+    tab,
+    "about-private-browsing-handoff",
+    Services.search.defaultEngine.name
+  );
 
   await Services.search.setDefault(addedEngine);
 
   // We only show the engine's own icon for app provided engines, otherwise show
   // a default. xref https://bugzilla.mozilla.org/show_bug.cgi?id=1449338#c19
   await ensureIcon(tab, "chrome://global/skin/icons/search-glass.svg");
+  await ensurePlaceholder(tab, "about-private-browsing-handoff-no-engine");
 
   await Services.search.setDefault(defaultEngine);
 
   await BrowserTestUtils.closeWindow(win);
 });
--- a/browser/locales/en-US/browser/aboutPrivateBrowsing.ftl
+++ b/browser/locales/en-US/browser/aboutPrivateBrowsing.ftl
@@ -1,19 +1,26 @@
 # 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/.
 
 privatebrowsingpage-open-private-window-label = Open a Private Window
     .accesskey = P
-about-private-browsing-search-placeholder = Search the Web
 about-private-browsing-info-title = You’re in a Private Window
 about-private-browsing-info-myths = Common myths about private browsing
-about-private-browsing =
-    .title = Search the Web
+# Variables
+#  $engine (String): the name of the user's default search engine
+about-private-browsing-handoff =
+    .title = Search with { $engine } or enter address
+about-private-browsing-handoff-no-engine =
+    .title = Search or enter address
+# Variables
+#  $engine (String): the name of the user's default search engine
+about-private-browsing-handoff-text = Search with { $engine } or enter address
+about-private-browsing-handoff-text-no-engine = Search or enter address
 about-private-browsing-not-private = You are currently not in a private window.
 about-private-browsing-info-description = { -brand-short-name } clears your search and browsing history when you quit the app or close all Private Browsing tabs and windows. While this doesn’t make you anonymous to websites or your internet service provider, it makes it easier to keep what you do online private from anyone else who uses this computer.
 
 about-private-browsing-need-more-privacy = Need more privacy?
 about-private-browsing-turn-on-vpn = Try { -mozilla-vpn-brand-name }
 
 # This string is the title for the banner for search engine selection
 # in a private window.
--- a/browser/locales/en-US/browser/newtab/newtab.ftl
+++ b/browser/locales/en-US/browser/newtab/newtab.ftl
@@ -13,23 +13,36 @@ newtab-personalize-button-label = Person
 
 ## Search box component.
 
 # "Search" is a verb/action
 newtab-search-box-search-button =
     .title = Search
     .aria-label = Search
 
-newtab-search-box-search-the-web-text = Search the Web
+# Variables
+#  $engine (String): the name of the user's default search engine
+newtab-search-box-handoff-text = Search with { $engine } or enter address
+newtab-search-box-handoff-text-no-engine = Search or enter address
+# Variables
+#  $engine (String): the name of the user's default search engine
+newtab-search-box-handoff-input =
+    .placeholder = Search with { $engine } or enter address
+    .title = Search with { $engine } or enter address
+    .aria-label = Search with { $engine } or enter address
+newtab-search-box-handoff-input-no-engine =
+    .placeholder = Search or enter address
+    .title = Search or enter address
+    .aria-label = Search or enter address
+
 newtab-search-box-search-the-web-input =
     .placeholder = Search the Web
     .title = Search the Web
     .aria-label = Search the Web
 
-newtab-search-box-text = Search the web
 newtab-search-box-input =
     .placeholder = Search the web
     .aria-label = Search the web
 
 ## Top Sites - General form dialog.
 
 newtab-topsites-add-search-engine-header = Add Search Engine
 newtab-topsites-add-topsites-header = New Top Site
--- a/toolkit/modules/RemotePageAccessManager.jsm
+++ b/toolkit/modules/RemotePageAccessManager.jsm
@@ -119,17 +119,21 @@ let RemotePageAccessManager = {
     },
     "about:privatebrowsing": {
       RPMSendAsyncMessage: [
         "OpenPrivateWindow",
         "SearchBannerDismissed",
         "OpenSearchPreferences",
         "SearchHandoff",
       ],
-      RPMSendQuery: ["ShouldShowSearchBanner", "ShouldShowVPNPromo"],
+      RPMSendQuery: [
+        "ShouldShowSearch",
+        "ShouldShowSearchBanner",
+        "ShouldShowVPNPromo",
+      ],
       RPMAddMessageListener: ["*"],
       RPMRemoveMessageListener: ["*"],
       RPMGetFormatURLPref: [
         "app.support.baseURL",
         "browser.privatebrowsing.vpnpromourl",
       ],
       RPMIsWindowPrivate: ["*"],
     },