Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / extensions / application_launch.cc
1 // Copyright (c) 2012 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/ui/extensions/application_launch.h"
6
7 #include <string>
8
9 #include "apps/launcher.h"
10 #include "base/metrics/histogram.h"
11 #include "chrome/browser/apps/per_app_settings_service.h"
12 #include "chrome/browser/apps/per_app_settings_service_factory.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/extensions/tab_helper.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/app_list/app_list_service.h"
17 #include "chrome/browser/ui/extensions/app_launch_params.h"
18 #include "chrome/browser/ui/extensions/application_launch_web_app.h"
19 #include "chrome/browser/ui/extensions/extension_enable_flow.h"
20 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
21 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
22 #include "chrome/common/url_constants.h"
23 #include "content/public/browser/web_contents.h"
24 #include "extensions/browser/extension_prefs.h"
25 #include "extensions/browser/extension_registry.h"
26 #include "extensions/browser/extension_system.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/features/feature.h"
29 #include "extensions/common/features/feature_provider.h"
30 #include "extensions/common/manifest_handlers/options_page_info.h"
31
32 using content::WebContents;
33 using extensions::Extension;
34 using extensions::ExtensionPrefs;
35 using extensions::ExtensionRegistry;
36
37 namespace {
38
39 #if !defined(USE_ATHENA)
40 // Shows the app list for |desktop_type| and returns the app list's window.
41 gfx::NativeWindow ShowAppListAndGetNativeWindow(
42       chrome::HostDesktopType desktop_type) {
43   AppListService* app_list_service = AppListService::Get(desktop_type);
44   app_list_service->Show();
45   return app_list_service->GetAppListWindow();
46 }
47 #endif
48
49 // Attempts to launch an app, prompting the user to enable it if necessary. If
50 // a prompt is required it will be shown inside the window returned by
51 // |parent_window_getter|.
52 // This class manages its own lifetime.
53 class EnableViaDialogFlow : public ExtensionEnableFlowDelegate {
54  public:
55   EnableViaDialogFlow(
56       ExtensionService* service,
57       Profile* profile,
58       const std::string& extension_id,
59       const base::Callback<gfx::NativeWindow(void)>& parent_window_getter,
60       const base::Closure& callback)
61       : service_(service),
62         profile_(profile),
63         extension_id_(extension_id),
64         parent_window_getter_(parent_window_getter),
65         callback_(callback) {
66   }
67
68   ~EnableViaDialogFlow() override {}
69
70   void Run() {
71     DCHECK(!service_->IsExtensionEnabled(extension_id_));
72     flow_.reset(new ExtensionEnableFlow(profile_, extension_id_, this));
73     flow_->StartForCurrentlyNonexistentWindow(parent_window_getter_);
74   }
75
76  private:
77   // ExtensionEnableFlowDelegate overrides.
78   void ExtensionEnableFlowFinished() override {
79     const Extension* extension =
80         service_->GetExtensionById(extension_id_, false);
81     if (!extension)
82       return;
83     callback_.Run();
84     delete this;
85   }
86
87   void ExtensionEnableFlowAborted(bool user_initiated) override { delete this; }
88
89   ExtensionService* service_;
90   Profile* profile_;
91   std::string extension_id_;
92   base::Callback<gfx::NativeWindow(void)> parent_window_getter_;
93   base::Closure callback_;
94   scoped_ptr<ExtensionEnableFlow> flow_;
95
96   DISALLOW_COPY_AND_ASSIGN(EnableViaDialogFlow);
97 };
98
99 const Extension* GetExtension(const AppLaunchParams& params) {
100   if (params.extension_id.empty())
101     return NULL;
102   ExtensionRegistry* registry = ExtensionRegistry::Get(params.profile);
103   return registry->GetExtensionById(params.extension_id,
104                                     ExtensionRegistry::ENABLED |
105                                         ExtensionRegistry::DISABLED |
106                                         ExtensionRegistry::TERMINATED);
107 }
108
109 // Get the launch URL for a given extension, with optional override/fallback.
110 // |override_url|, if non-empty, will be preferred over the extension's
111 // launch url.
112 GURL UrlForExtension(const extensions::Extension* extension,
113                      const GURL& override_url) {
114   if (!extension)
115     return override_url;
116
117   GURL url;
118   if (!override_url.is_empty()) {
119     DCHECK(extension->web_extent().MatchesURL(override_url) ||
120            override_url.GetOrigin() == extension->url());
121     url = override_url;
122   } else {
123     url = extensions::AppLaunchInfo::GetFullLaunchURL(extension);
124   }
125
126   // For extensions lacking launch urls, determine a reasonable fallback.
127   if (!url.is_valid()) {
128     url = extensions::OptionsPageInfo::GetOptionsPage(extension);
129     if (!url.is_valid())
130       url = GURL(chrome::kChromeUIExtensionsURL);
131   }
132
133   return url;
134 }
135
136 WebContents* OpenEnabledApplication(const AppLaunchParams& params) {
137   const Extension* extension = GetExtension(params);
138   if (!extension)
139     return NULL;
140   Profile* profile = params.profile;
141
142   WebContents* tab = NULL;
143   ExtensionPrefs* prefs = ExtensionPrefs::Get(profile);
144   prefs->SetActiveBit(extension->id(), true);
145
146   UMA_HISTOGRAM_ENUMERATION(
147       "Extensions.AppLaunchContainer", params.container, 100);
148
149   if (CanLaunchViaEvent(extension)) {
150     // Remember what desktop the launch happened on so that when the app opens a
151     // window we can open them on the right desktop.
152     PerAppSettingsServiceFactory::GetForBrowserContext(profile)->
153         SetDesktopLastLaunchedFrom(extension->id(), params.desktop_type);
154
155     apps::LaunchPlatformAppWithCommandLine(profile,
156                                            extension,
157                                            params.command_line,
158                                            params.current_directory,
159                                            params.source);
160     return NULL;
161   }
162
163   // Record v1 app launch. Platform app launch is recorded when dispatching
164   // the onLaunched event.
165   prefs->SetLastLaunchTime(extension->id(), base::Time::Now());
166
167   GURL url = UrlForExtension(extension, params.override_url);
168   switch (params.container) {
169     case extensions::LAUNCH_CONTAINER_NONE: {
170       NOTREACHED();
171       break;
172     }
173     case extensions::LAUNCH_CONTAINER_PANEL:
174     case extensions::LAUNCH_CONTAINER_WINDOW:
175       tab = OpenWebAppWindow(params, url);
176       break;
177     case extensions::LAUNCH_CONTAINER_TAB: {
178       tab = OpenWebAppTab(params, url);
179       break;
180     }
181     default:
182       NOTREACHED();
183       break;
184   }
185   return tab;
186 }
187
188 }  // namespace
189
190 WebContents* OpenApplication(const AppLaunchParams& params) {
191   return OpenEnabledApplication(params);
192 }
193
194 void OpenApplicationWithReenablePrompt(const AppLaunchParams& params) {
195   const Extension* extension = GetExtension(params);
196   if (!extension)
197     return;
198   Profile* profile = params.profile;
199
200   ExtensionService* service =
201       extensions::ExtensionSystem::Get(profile)->extension_service();
202   if (!service->IsExtensionEnabled(extension->id()) ||
203       extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
204           extension->id(), extensions::ExtensionRegistry::TERMINATED)) {
205   base::Callback<gfx::NativeWindow(void)> dialog_parent_window_getter;
206   // TODO(pkotwicz): Figure out which window should be used as the parent for
207   // the "enable application" dialog in Athena.
208 #if !defined(USE_ATHENA)
209   dialog_parent_window_getter =
210       base::Bind(&ShowAppListAndGetNativeWindow, params.desktop_type);
211 #endif
212     (new EnableViaDialogFlow(
213         service, profile, extension->id(), dialog_parent_window_getter,
214         base::Bind(base::IgnoreResult(OpenEnabledApplication), params)))->Run();
215     return;
216   }
217
218   OpenEnabledApplication(params);
219 }
220
221 WebContents* OpenAppShortcutWindow(Profile* profile,
222                                    const GURL& url) {
223   AppLaunchParams launch_params(
224       profile,
225       NULL,  // this is a URL app.  No extension.
226       extensions::LAUNCH_CONTAINER_WINDOW,
227       NEW_WINDOW);
228   launch_params.override_url = url;
229
230   WebContents* tab = OpenWebAppWindow(launch_params, url);
231
232   if (!tab)
233     return NULL;
234
235   extensions::TabHelper::FromWebContents(tab)->UpdateShortcutOnLoadComplete();
236
237   return tab;
238 }
239
240 bool CanLaunchViaEvent(const extensions::Extension* extension) {
241   const extensions::FeatureProvider* feature_provider =
242       extensions::FeatureProvider::GetAPIFeatures();
243   extensions::Feature* feature = feature_provider->GetFeature("app.runtime");
244   return feature->IsAvailableToExtension(extension).is_available();
245 }