1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/apps/app_service/launch_utils.h"
6 
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "chrome/browser/extensions/tab_helper.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_navigator.h"
13 #include "chrome/browser/ui/browser_navigator_params.h"
14 #include "chrome/browser/ui/browser_window.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
16 #include "chrome/browser/web_applications/components/app_registrar.h"
17 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
18 #include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
19 #include "chrome/browser/web_applications/components/web_app_utils.h"
20 #include "chrome/browser/web_applications/web_app_tab_helper.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/webui_url_constants.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/common/extension.h"
25 #include "ui/events/event_constants.h"
26 #include "url/gurl.h"
27 
28 namespace apps {
29 
GetAppIdForWebContents(content::WebContents * web_contents)30 std::string GetAppIdForWebContents(content::WebContents* web_contents) {
31   std::string app_id;
32 
33   web_app::WebAppTabHelperBase* web_app_tab_helper =
34       web_app::WebAppTabHelperBase::FromWebContents(web_contents);
35   // web_app_tab_helper is nullptr in some unit tests.
36   if (web_app_tab_helper) {
37     app_id = web_app_tab_helper->GetAppId();
38   }
39 
40   if (app_id.empty()) {
41     extensions::TabHelper* extensions_tab_helper =
42         extensions::TabHelper::FromWebContents(web_contents);
43     // extensions_tab_helper is nullptr in some tests.
44     if (extensions_tab_helper) {
45       app_id = extensions_tab_helper->GetExtensionAppId();
46     }
47   }
48 
49   return app_id;
50 }
51 
IsInstalledApp(Profile * profile,const std::string & app_id)52 bool IsInstalledApp(Profile* profile, const std::string& app_id) {
53   const extensions::Extension* extension =
54       extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension(
55           app_id);
56   if (extension && !extension->from_bookmark()) {
57     DCHECK(extension->is_app());
58     return true;
59   }
60   web_app::AppRegistrar& registrar =
61       web_app::WebAppProviderBase::GetProviderBase(profile)->registrar();
62   return registrar.IsInstalled(app_id);
63 }
64 
SetAppIdForWebContents(Profile * profile,content::WebContents * web_contents,const std::string & app_id)65 void SetAppIdForWebContents(Profile* profile,
66                             content::WebContents* web_contents,
67                             const std::string& app_id) {
68   if (!web_app::AreWebAppsEnabled(profile)) {
69     return;
70   }
71   extensions::TabHelper::CreateForWebContents(web_contents);
72   web_app::WebAppTabHelper::CreateForWebContents(web_contents);
73   const extensions::Extension* extension =
74       extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension(
75           app_id);
76   if (extension && !extension->from_bookmark()) {
77     DCHECK(extension->is_app());
78     web_app::WebAppTabHelperBase::FromWebContents(web_contents)
79         ->SetAppId(std::string());
80     extensions::TabHelper::FromWebContents(web_contents)
81         ->SetExtensionAppById(app_id);
82   } else {
83     web_app::AppRegistrar& registrar =
84         web_app::WebAppProviderBase::GetProviderBase(profile)->registrar();
85     web_app::WebAppTabHelperBase::FromWebContents(web_contents)
86         ->SetAppId(registrar.IsInstalled(app_id) ? app_id : std::string());
87     extensions::TabHelper::FromWebContents(web_contents)
88         ->SetExtensionAppById(std::string());
89   }
90 }
91 
GetLaunchFilesFromCommandLine(const base::CommandLine & command_line)92 std::vector<base::FilePath> GetLaunchFilesFromCommandLine(
93     const base::CommandLine& command_line) {
94   std::vector<base::FilePath> launch_files;
95   if (!command_line.HasSwitch(switches::kAppId)) {
96     return launch_files;
97   }
98 
99   // Assume all args passed were intended as files to pass to the app.
100   launch_files.reserve(command_line.GetArgs().size());
101   for (const auto& arg : command_line.GetArgs()) {
102     base::FilePath path(arg);
103     if (path.empty()) {
104       continue;
105     }
106 
107     launch_files.push_back(path);
108   }
109 
110   return launch_files;
111 }
112 
CreateBrowserWithNewTabPage(Profile * profile)113 Browser* CreateBrowserWithNewTabPage(Profile* profile) {
114   Browser::CreateParams create_params(profile, /*user_gesture=*/false);
115   Browser* browser = Browser::Create(create_params);
116 
117   NavigateParams params(browser, GURL(chrome::kChromeUINewTabURL),
118                         ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
119   params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
120   params.tabstrip_add_types = TabStripModel::ADD_ACTIVE;
121   Navigate(&params);
122 
123   browser->window()->Show();
124   return browser;
125 }
126 
CreateAppIdLaunchParamsWithEventFlags(const std::string & app_id,int event_flags,apps::mojom::AppLaunchSource source,int64_t display_id,apps::mojom::LaunchContainer fallback_container)127 AppLaunchParams CreateAppIdLaunchParamsWithEventFlags(
128     const std::string& app_id,
129     int event_flags,
130     apps::mojom::AppLaunchSource source,
131     int64_t display_id,
132     apps::mojom::LaunchContainer fallback_container) {
133   WindowOpenDisposition raw_disposition =
134       ui::DispositionFromEventFlags(event_flags);
135 
136   apps::mojom::LaunchContainer container;
137   WindowOpenDisposition disposition;
138   if (raw_disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
139       raw_disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB) {
140     container = apps::mojom::LaunchContainer::kLaunchContainerTab;
141     disposition = raw_disposition;
142   } else if (raw_disposition == WindowOpenDisposition::NEW_WINDOW) {
143     container = apps::mojom::LaunchContainer::kLaunchContainerWindow;
144     disposition = raw_disposition;
145   } else {
146     // Look at preference to find the right launch container.  If no preference
147     // is set, launch as a regular tab.
148     container = fallback_container;
149     disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
150   }
151   return AppLaunchParams(app_id, container, disposition, source, display_id);
152 }
153 
CreateAppLaunchParamsForIntent(const std::string & app_id,int32_t event_flags,apps::mojom::AppLaunchSource source,int64_t display_id,apps::mojom::LaunchContainer fallback_container,apps::mojom::IntentPtr && intent)154 apps::AppLaunchParams CreateAppLaunchParamsForIntent(
155     const std::string& app_id,
156     int32_t event_flags,
157     apps::mojom::AppLaunchSource source,
158     int64_t display_id,
159     apps::mojom::LaunchContainer fallback_container,
160     apps::mojom::IntentPtr&& intent) {
161   auto params = CreateAppIdLaunchParamsWithEventFlags(
162       app_id, event_flags, source, display_id, fallback_container);
163 
164   if (intent->url.has_value()) {
165     params.source = apps::mojom::AppLaunchSource::kSourceIntentUrl;
166     params.override_url = intent->url.value();
167     LOG(ERROR) << "url is:" << params.override_url.spec();
168     std::string port;
169     if (intent->url->has_port()) {
170       port = ":" + intent->url->port();
171     }
172     params.override_url =
173         GURL(intent->url->scheme() + url::kStandardSchemeSeparator +
174              intent->url->host() + port + intent->url->path());
175     LOG(ERROR) << "url is:" << params.override_url.spec();
176     DCHECK(params.override_url.is_valid());
177   }
178 
179   params.intent = std::move(intent);
180 
181   return params;
182 }
183 
GetAppLaunchSource(apps::mojom::LaunchSource launch_source)184 apps::mojom::AppLaunchSource GetAppLaunchSource(
185     apps::mojom::LaunchSource launch_source) {
186   switch (launch_source) {
187     case apps::mojom::LaunchSource::kUnknown:
188     case apps::mojom::LaunchSource::kFromAppListGrid:
189     case apps::mojom::LaunchSource::kFromAppListGridContextMenu:
190     case apps::mojom::LaunchSource::kFromAppListQuery:
191     case apps::mojom::LaunchSource::kFromAppListQueryContextMenu:
192     case apps::mojom::LaunchSource::kFromAppListRecommendation:
193     case apps::mojom::LaunchSource::kFromParentalControls:
194     case apps::mojom::LaunchSource::kFromShelf:
195     case apps::mojom::LaunchSource::kFromLink:
196     case apps::mojom::LaunchSource::kFromOmnibox:
197     case apps::mojom::LaunchSource::kFromOtherApp:
198     case apps::mojom::LaunchSource::kFromMenu:
199     case apps::mojom::LaunchSource::kFromSharesheet:
200       return apps::mojom::AppLaunchSource::kSourceAppLauncher;
201     case apps::mojom::LaunchSource::kFromKeyboard:
202       return apps::mojom::AppLaunchSource::kSourceKeyboard;
203     case apps::mojom::LaunchSource::kFromFileManager:
204       return apps::mojom::AppLaunchSource::kSourceFileHandler;
205     case apps::mojom::LaunchSource::kFromChromeInternal:
206     case apps::mojom::LaunchSource::kFromReleaseNotesNotification:
207       return apps::mojom::AppLaunchSource::kSourceChromeInternal;
208     case apps::mojom::LaunchSource::kFromInstalledNotification:
209       return apps::mojom::AppLaunchSource::kSourceInstalledNotification;
210     case apps::mojom::LaunchSource::kFromTest:
211       return apps::mojom::AppLaunchSource::kSourceTest;
212     case apps::mojom::LaunchSource::kFromArc:
213       return apps::mojom::AppLaunchSource::kSourceArc;
214   }
215 }
216 
GetEventFlags(apps::mojom::LaunchContainer container,WindowOpenDisposition disposition,bool prefer_container)217 int GetEventFlags(apps::mojom::LaunchContainer container,
218                   WindowOpenDisposition disposition,
219                   bool prefer_container) {
220   if (prefer_container) {
221     return ui::EF_NONE;
222   }
223 
224   switch (disposition) {
225     case WindowOpenDisposition::NEW_WINDOW:
226       return ui::EF_SHIFT_DOWN;
227     case WindowOpenDisposition::NEW_BACKGROUND_TAB:
228       return ui::EF_MIDDLE_MOUSE_BUTTON;
229     case WindowOpenDisposition::NEW_FOREGROUND_TAB:
230       return ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_SHIFT_DOWN;
231     default:
232       NOTREACHED();
233       return ui::EF_NONE;
234   }
235 }
236 
237 }  // namespace apps
238