desktop-pwas: support reparenting into PWA windows

The code reparenting tabs was needlessly extensions specific.

[email protected]
[email protected]

Bug: 966288
Change-Id: I6e82e205c15018f52d028709b05ff59aac7bf8b8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1743299
Commit-Queue: Eric Willigers <[email protected]>
Reviewed-by: Alexey Baskakov <[email protected]>
Reviewed-by: Alan Cutter <[email protected]>
Reviewed-by: Michael Wasserman <[email protected]>
Cr-Commit-Position: refs/heads/master@{#687914}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index ba41be2..b79b932d 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3757,6 +3757,8 @@
       "web_applications/web_app_dialog_utils.h",
       "web_applications/web_app_launch_manager.cc",
       "web_applications/web_app_launch_manager.h",
+      "web_applications/web_app_launch_utils.cc",
+      "web_applications/web_app_launch_utils.h",
       "web_applications/web_app_metrics.cc",
       "web_applications/web_app_metrics.h",
       "web_applications/web_app_metrics_factory.cc",
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 3b69230..e83107e5 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -38,12 +38,11 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
 #include "chrome/browser/ui/page_info/page_info_dialog.h"
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/ui/webui/inspect_ui.h"
 #include "chrome/common/content_restriction.h"
 #include "chrome/common/pref_names.h"
@@ -458,7 +457,7 @@
       break;
     case IDC_OPEN_IN_PWA_WINDOW:
       base::RecordAction(base::UserMetricsAction("OpenActiveTabInPwaWindow"));
-      ReparentSecureActiveTabIntoPwaWindow(browser_);
+      web_app::ReparentWebAppForSecureActiveTab(browser_);
       break;
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index b5baf44..47f664ae 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -9,7 +9,6 @@
 
 #include "apps/launcher.h"
 #include "base/bind.h"
-#include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
@@ -32,7 +31,6 @@
 #include "chrome/browser/ui/extensions/extension_enable_flow.h"
 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
 #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_tab_helper.h"
 #include "chrome/browser/web_launch/web_launch_files_helper.h"
@@ -344,26 +342,6 @@
   return tab;
 }
 
-Browser* ReparentWebContentsWithBrowserCreateParams(
-    content::WebContents* contents,
-    const Browser::CreateParams& browser_params) {
-  Browser* source_browser = chrome::FindBrowserWithWebContents(contents);
-  Browser* target_browser = Browser::Create(browser_params);
-
-  TabStripModel* source_tabstrip = source_browser->tab_strip_model();
-  // Avoid causing the existing browser window to close if this is the last tab
-  // remaining.
-  if (source_tabstrip->count() == 1)
-    chrome::NewTab(source_browser);
-  target_browser->tab_strip_model()->AppendWebContents(
-      source_tabstrip->DetachWebContentsAt(
-          source_tabstrip->GetIndexOfWebContents(contents)),
-      true);
-  target_browser->window()->Show();
-
-  return target_browser;
-}
-
 }  // namespace
 
 WebContents* OpenApplication(const AppLaunchParams& params) {
@@ -495,38 +473,3 @@
       extensions::FeatureProvider::GetAPIFeature("app.runtime");
   return feature && feature->IsAvailableToExtension(extension).is_available();
 }
-
-Browser* ReparentWebContentsIntoAppBrowser(content::WebContents* contents,
-                                           const std::string& app_id) {
-  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-  // Incognito tabs reparent correctly, but remain incognito without any
-  // indication to the user, so disallow it.
-  DCHECK(!profile->IsOffTheRecord());
-  Browser::CreateParams browser_params(Browser::CreateParams::CreateForApp(
-      web_app::GenerateApplicationNameFromAppId(app_id),
-      true /* trusted_source */, gfx::Rect(), profile,
-      true /* user_gesture */));
-  return ReparentWebContentsWithBrowserCreateParams(contents, browser_params);
-}
-
-Browser* ReparentWebContentsForFocusMode(content::WebContents* contents) {
-  DCHECK(base::FeatureList::IsEnabled(features::kFocusMode));
-  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-  // TODO(crbug.com/941577): Remove DCHECK when focus mode is permitted in guest
-  // and incognito sessions.
-  DCHECK(!profile->IsOffTheRecord());
-  Browser::CreateParams browser_params(Browser::CreateParams::CreateForApp(
-      web_app::GenerateApplicationNameForFocusMode(), true /* trusted_source */,
-      gfx::Rect(), profile, true /* user_gesture */));
-  browser_params.is_focus_mode = true;
-  return ReparentWebContentsWithBrowserCreateParams(contents, browser_params);
-}
-
-Browser* ReparentSecureActiveTabIntoPwaWindow(Browser* browser) {
-  const extensions::Extension* extension =
-      extensions::util::GetPwaForSecureActiveTab(browser);
-  if (!extension)
-    return nullptr;
-  return ReparentWebContentsIntoAppBrowser(
-      browser->tab_strip_model()->GetActiveWebContents(), extension->id());
-}
diff --git a/chrome/browser/ui/extensions/application_launch.h b/chrome/browser/ui/extensions/application_launch.h
index 189e0cea..558b180 100644
--- a/chrome/browser/ui/extensions/application_launch.h
+++ b/chrome/browser/ui/extensions/application_launch.h
@@ -54,18 +54,4 @@
 // chrome.app.runtime.onLaunched event.
 bool CanLaunchViaEvent(const extensions::Extension* extension);
 
-// Reparents |contents| into a new app browser for |app_id|.
-// TODO(loyso): Move this util to ui/web_applications/ directory. It is
-// universal for any AppBrowserController.
-Browser* ReparentWebContentsIntoAppBrowser(content::WebContents* contents,
-                                           const std::string& app_id);
-
-// Reparents contents to a new app browser when entering the Focus Mode.
-Browser* ReparentWebContentsForFocusMode(content::WebContents* contents);
-
-// Reparents the active tab into a new app browser for the PWA that has the
-// tab's URL in its scope. Does nothing if the tab is not secure or there is no
-// applicable PWA.
-Browser* ReparentSecureActiveTabIntoPwaWindow(Browser* browser);
-
 #endif  // CHROME_BROWSER_UI_EXTENSIONS_APPLICATION_LAUNCH_H_
diff --git a/chrome/browser/ui/extensions/application_launch_browsertest.cc b/chrome/browser/ui/extensions/application_launch_browsertest.cc
index 2d0fa5a..53f03db 100644
--- a/chrome/browser/ui/extensions/application_launch_browsertest.cc
+++ b/chrome/browser/ui/extensions/application_launch_browsertest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/chrome_test_suite.h"
 #include "chrome/test/base/test_launcher_utils.h"
@@ -31,8 +31,8 @@
   const GURL url("http://aaa.com/empty.html");
   ui_test_utils::NavigateToURL(browser(), url);
 
-  Browser* app_browser =
-      ReparentWebContentsForFocusMode(GetWebContentsForTab(browser(), 0));
+  Browser* app_browser = web_app::ReparentWebContentsForFocusMode(
+      GetWebContentsForTab(browser(), 0));
   EXPECT_TRUE(app_browser->is_type_app());
   EXPECT_NE(app_browser, browser());
 
@@ -57,8 +57,8 @@
   EXPECT_FALSE(browser()->is_focus_mode());
   ASSERT_EQ(3, browser()->tab_strip_model()->count());
 
-  Browser* app_browser =
-      ReparentWebContentsForFocusMode(GetWebContentsForTab(browser(), 1));
+  Browser* app_browser = web_app::ReparentWebContentsForFocusMode(
+      GetWebContentsForTab(browser(), 1));
   EXPECT_TRUE(app_browser->is_type_app());
   EXPECT_NE(app_browser, browser());
   EXPECT_EQ(url, GetWebContentsForTab(app_browser, 0)->GetURL());
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index 0af72f5..bbec492 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -40,13 +40,13 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/app_launch_params.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/extensions/hosted_app_menu_model.h"
 #include "chrome/browser/ui/page_info/page_info_dialog.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/common/chrome_features.h"
@@ -537,7 +537,7 @@
 }
 
 // Tests that the WebContents of an app window launched using
-// ReparentWebContentsIntoAppBrowser has the correct prefs.
+// web_app::ReparentWebContentsIntoAppBrowser has the correct prefs.
 IN_PROC_BROWSER_TEST_P(HostedAppTest, WebContentsPrefsReparentWebContents) {
   SetupApp("https_app");
 
@@ -546,7 +546,7 @@
   CheckWebContentsDoesNotHaveAppPrefs(current_tab);
 
   Browser* app_browser =
-      ReparentWebContentsIntoAppBrowser(current_tab, app_->id());
+      web_app::ReparentWebContentsIntoAppBrowser(current_tab, app_->id());
   ASSERT_NE(browser(), app_browser);
 
   CheckWebContentsHasAppPrefs(
@@ -1225,7 +1225,7 @@
 
 // Tests that the command for OpenActiveTabInPwaWindow is available for secure
 // pages in an app's scope.
-IN_PROC_BROWSER_TEST_P(SharedPWATest, ReparentSecureActiveTabIntoPwaWindow) {
+IN_PROC_BROWSER_TEST_P(SharedPWATest, ReparentWebAppForSecureActiveTab) {
   ASSERT_TRUE(https_server()->Start());
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -1239,7 +1239,7 @@
   EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, browser()),
             kEnabled);
 
-  Browser* app_browser = ReparentSecureActiveTabIntoPwaWindow(browser());
+  Browser* app_browser = web_app::ReparentWebAppForSecureActiveTab(browser());
 
   ASSERT_EQ(app_browser->app_controller()->GetAppId(), app_->id());
 }
@@ -1252,7 +1252,7 @@
   InstallSecurePWA();
   NavigateToURLAndWait(browser(), GetSecureAppURL());
 
-  Browser* app_browser = ReparentSecureActiveTabIntoPwaWindow(browser());
+  Browser* app_browser = web_app::ReparentWebAppForSecureActiveTab(browser());
   ASSERT_EQ(app_browser->app_controller()->GetAppId(), app_->id());
 
   ASSERT_TRUE(IsBrowserOpen(browser()));
@@ -1331,11 +1331,11 @@
   CheckMixedContentLoaded(browser());
   EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, browser()),
             kNotPresent);
-  EXPECT_EQ(ReparentSecureActiveTabIntoPwaWindow(browser()), nullptr);
+  EXPECT_EQ(web_app::ReparentWebAppForSecureActiveTab(browser()), nullptr);
 }
 
-// Tests that when calling ReparentWebContentsIntoAppBrowser, mixed content
-// cannot be loaded in the new app window.
+// Tests that when calling web_app::ReparentWebContentsIntoAppBrowser, mixed
+// content cannot be loaded in the new app window.
 IN_PROC_BROWSER_TEST_P(HostedAppPWAOnlyTestWithAutoupgradesDisabled,
                        MixedContentReparentWebContentsIntoAppBrowser) {
   ASSERT_TRUE(https_server()->Start());
@@ -1354,7 +1354,7 @@
             kNotPresent);
 
   Browser* app_browser =
-      ReparentWebContentsIntoAppBrowser(tab_contents, app_->id());
+      web_app::ReparentWebContentsIntoAppBrowser(tab_contents, app_->id());
 
   ASSERT_NE(app_browser, browser());
   ASSERT_EQ(GetMixedContentAppURL(), app_browser->tab_strip_model()
@@ -1399,7 +1399,7 @@
   NavigateToURLAndWait(browser(), GetSecureIFrameAppURL());
   CheckMixedContentFailedToLoad(browser());
 
-  app_browser_ = ReparentWebContentsIntoAppBrowser(
+  app_browser_ = web_app::ReparentWebContentsIntoAppBrowser(
       browser()->tab_strip_model()->GetActiveWebContents(), app_->id());
   CheckMixedContentFailedToLoad(app_browser_);
 
diff --git a/chrome/browser/ui/manifest_web_app_browsertest.cc b/chrome/browser/ui/manifest_web_app_browsertest.cc
index edc92df3..fed1acdb 100644
--- a/chrome/browser/ui/manifest_web_app_browsertest.cc
+++ b/chrome/browser/ui/manifest_web_app_browsertest.cc
@@ -9,8 +9,8 @@
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/manifest_web_app_browser_controller.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/test/browser_test_utils.h"
@@ -40,7 +40,7 @@
   feature_list.InitAndEnableFeature(features::kFocusMode);
   const GURL url("http://example.org/");
   ui_test_utils::NavigateToURL(browser(), url);
-  Browser* app_browser = ReparentWebContentsForFocusMode(
+  Browser* app_browser = web_app::ReparentWebContentsForFocusMode(
       browser()->tab_strip_model()->GetWebContentsAt(0));
   ASSERT_TRUE(app_browser->is_focus_mode());
   ASSERT_FALSE(browser()->is_focus_mode());
@@ -58,7 +58,7 @@
 IN_PROC_BROWSER_TEST_F(ManifestWebAppTest, MetricsTest) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(features::kFocusMode);
-  Browser* app_browser = ReparentWebContentsForFocusMode(
+  Browser* app_browser = web_app::ReparentWebContentsForFocusMode(
       browser()->tab_strip_model()->GetWebContentsAt(0));
 
   const base::TimeDelta duration = base::TimeDelta::FromSeconds(5);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 57699df..9f1a114 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -28,13 +28,13 @@
 #include "chrome/browser/send_tab_to_self/send_tab_to_self_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/tabs/tab_group_id.h"
 #include "chrome/browser/ui/tabs/tab_group_visual_data.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/ui/web_contents_sizer.h"
 #include "chrome/common/url_constants.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -1293,7 +1293,7 @@
       base::RecordAction(UserMetricsAction("TabContextMenu_FocusMode"));
       std::vector<int> indices = GetIndicesForCommand(context_index);
       WebContents* contents = GetWebContentsAt(indices[0]);
-      ReparentWebContentsForFocusMode(contents);
+      web_app::ReparentWebContentsForFocusMode(contents);
       break;
     }
 
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index 2ff10a67..ee9d26b 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/banners/app_banner_manager.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/defaults.h"
-#include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/media/router/media_router_feature.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
@@ -44,7 +43,9 @@
 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
 #include "chrome/browser/ui/ui_features.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
@@ -776,14 +777,17 @@
 
   AddItemWithStringId(IDC_FIND, IDS_FIND);
 
-  const extensions::Extension* pwa =
-      extensions::util::GetPwaForSecureActiveTab(browser_);
-  if (pwa) {
+  base::Optional<web_app::AppId> app_id =
+      web_app::GetPwaForSecureActiveTab(browser());
+  if (app_id) {
+    auto* provider = web_app::WebAppProvider::Get(browser()->profile());
     AddItem(IDC_OPEN_IN_PWA_WINDOW,
             l10n_util::GetStringFUTF16(
                 IDS_OPEN_IN_APP_WINDOW,
-                gfx::TruncateString(base::UTF8ToUTF16(pwa->name()),
-                                    kMaxAppNameLength, gfx::CHARACTER_BREAK)));
+                gfx::TruncateString(
+                    base::UTF8ToUTF16(
+                        provider->registrar().GetAppShortName(*app_id)),
+                    kMaxAppNameLength, gfx::CHARACTER_BREAK)));
   } else {
     base::Optional<base::string16> install_pwa_item_name =
         GetInstallPWAAppMenuItemName(browser_);
diff --git a/chrome/browser/ui/web_applications/web_app_launch_utils.cc b/chrome/browser/ui/web_applications/web_app_launch_utils.cc
new file mode 100644
index 0000000..ae616ea
--- /dev/null
+++ b/chrome/browser/ui/web_applications/web_app_launch_utils.cc
@@ -0,0 +1,104 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
+
+#include "base/feature_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/common/chrome_features.h"
+#include "components/omnibox/browser/location_bar_model.h"
+#include "content/public/browser/web_contents.h"
+
+namespace {
+
+Browser* ReparentWebContentsWithBrowserCreateParams(
+    content::WebContents* contents,
+    const Browser::CreateParams& browser_params) {
+  Browser* source_browser = chrome::FindBrowserWithWebContents(contents);
+  Browser* target_browser = Browser::Create(browser_params);
+
+  TabStripModel* source_tabstrip = source_browser->tab_strip_model();
+  // Avoid causing the existing browser window to close if this is the last tab
+  // remaining.
+  if (source_tabstrip->count() == 1)
+    chrome::NewTab(source_browser);
+  target_browser->tab_strip_model()->AppendWebContents(
+      source_tabstrip->DetachWebContentsAt(
+          source_tabstrip->GetIndexOfWebContents(contents)),
+      true);
+  target_browser->window()->Show();
+
+  return target_browser;
+}
+
+}  // namespace
+
+namespace web_app {
+
+base::Optional<AppId> GetPwaForSecureActiveTab(Browser* browser) {
+  switch (browser->location_bar_model()->GetSecurityLevel()) {
+    case security_state::SECURITY_LEVEL_COUNT:
+      NOTREACHED();
+      FALLTHROUGH;
+    case security_state::NONE:
+    case security_state::HTTP_SHOW_WARNING:
+    case security_state::DANGEROUS:
+      return base::nullopt;
+    case security_state::EV_SECURE:
+    case security_state::SECURE:
+    case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
+      break;
+  }
+  content::WebContents* web_contents =
+      browser->tab_strip_model()->GetActiveWebContents();
+  WebAppProvider* provider = WebAppProvider::Get(browser->profile());
+  if (!provider)
+    return base::nullopt;
+
+  return provider->registrar().FindAppWithUrlInScope(
+      web_contents->GetMainFrame()->GetLastCommittedURL());
+}
+
+Browser* ReparentWebAppForSecureActiveTab(Browser* browser) {
+  base::Optional<AppId> app_id = GetPwaForSecureActiveTab(browser);
+  if (!app_id)
+    return nullptr;
+  return ReparentWebContentsIntoAppBrowser(
+      browser->tab_strip_model()->GetActiveWebContents(), *app_id);
+}
+
+Browser* ReparentWebContentsIntoAppBrowser(content::WebContents* contents,
+                                           const AppId& app_id) {
+  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
+  // Incognito tabs reparent correctly, but remain incognito without any
+  // indication to the user, so disallow it.
+  DCHECK(!profile->IsOffTheRecord());
+  Browser::CreateParams browser_params(Browser::CreateParams::CreateForApp(
+      web_app::GenerateApplicationNameFromAppId(app_id),
+      true /* trusted_source */, gfx::Rect(), profile,
+      true /* user_gesture */));
+  return ReparentWebContentsWithBrowserCreateParams(contents, browser_params);
+}
+
+Browser* ReparentWebContentsForFocusMode(content::WebContents* contents) {
+  DCHECK(base::FeatureList::IsEnabled(features::kFocusMode));
+  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
+  // TODO(crbug.com/941577): Remove DCHECK when focus mode is permitted in guest
+  // and incognito sessions.
+  DCHECK(!profile->IsOffTheRecord());
+  Browser::CreateParams browser_params(Browser::CreateParams::CreateForApp(
+      web_app::GenerateApplicationNameForFocusMode(), true /* trusted_source */,
+      gfx::Rect(), profile, true /* user_gesture */));
+  browser_params.is_focus_mode = true;
+  return ReparentWebContentsWithBrowserCreateParams(contents, browser_params);
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/ui/web_applications/web_app_launch_utils.h b/chrome/browser/ui/web_applications/web_app_launch_utils.h
new file mode 100644
index 0000000..bddc37d
--- /dev/null
+++ b/chrome/browser/ui/web_applications/web_app_launch_utils.h
@@ -0,0 +1,37 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_LAUNCH_UTILS_H_
+#define CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_LAUNCH_UTILS_H_
+
+#include <string>
+
+#include "base/optional.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+
+class Browser;
+
+namespace content {
+class WebContents;
+}
+
+namespace web_app {
+
+base::Optional<AppId> GetPwaForSecureActiveTab(Browser* browser);
+
+// Reparents the active tab into a new app browser for the web app that has the
+// tab's URL in its scope. Does nothing if the tab is not secure or there is no
+// applicable web app.
+Browser* ReparentWebAppForSecureActiveTab(Browser* browser);
+
+// Reparents |contents| into a new app browser for |app_id|.
+Browser* ReparentWebContentsIntoAppBrowser(content::WebContents* contents,
+                                           const AppId& app_id);
+
+// Reparents contents to a new app browser when entering the Focus Mode.
+Browser* ReparentWebContentsForFocusMode(content::WebContents* contents);
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_LAUNCH_UTILS_H_
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
index b464137..a58aee1d 100644
--- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
+++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
@@ -11,9 +11,9 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_manager.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"