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(¶ms);
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