1 // Copyright 2013 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/ephemeral_app_launcher.h"
6
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/extensions/extension_install_prompt.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_system.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/extensions/application_launch.h"
13 #include "content/public/browser/notification_details.h"
14 #include "content/public/browser/notification_source.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/browser/web_contents_view.h"
17
18 using content::WebContents;
19 using extensions::Extension;
20 using extensions::ExtensionSystem;
21 using extensions::WebstoreInstaller;
22
23 namespace {
24
25 const char kExtensionTypeError[] = "Ephemeral extensions are not permitted";
26
ProfileForWebContents(content::WebContents * contents)27 Profile* ProfileForWebContents(content::WebContents* contents) {
28 if (!contents)
29 return NULL;
30
31 return Profile::FromBrowserContext(contents->GetBrowserContext());
32 }
33
NativeWindowForWebContents(content::WebContents * contents)34 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
35 if (!contents)
36 return NULL;
37
38 return contents->GetView()->GetTopLevelNativeWindow();
39 }
40
41 } // namespace
42
43 // static
44 scoped_refptr<EphemeralAppLauncher>
CreateForLauncher(const std::string & webstore_item_id,Profile * profile,gfx::NativeWindow parent_window,const Callback & callback)45 EphemeralAppLauncher::CreateForLauncher(
46 const std::string& webstore_item_id,
47 Profile* profile,
48 gfx::NativeWindow parent_window,
49 const Callback& callback) {
50 scoped_refptr<EphemeralAppLauncher> installer =
51 new EphemeralAppLauncher(webstore_item_id,
52 profile,
53 parent_window,
54 callback);
55 installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_APP_LAUNCHER);
56 return installer;
57 }
58
59 // static
60 scoped_refptr<EphemeralAppLauncher>
CreateForLink(const std::string & webstore_item_id,content::WebContents * web_contents)61 EphemeralAppLauncher::CreateForLink(
62 const std::string& webstore_item_id,
63 content::WebContents* web_contents) {
64 scoped_refptr<EphemeralAppLauncher> installer =
65 new EphemeralAppLauncher(webstore_item_id,
66 web_contents,
67 Callback());
68 installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_OTHER);
69 return installer;
70 }
71
Start()72 void EphemeralAppLauncher::Start() {
73 ExtensionService* extension_service =
74 extensions::ExtensionSystem::Get(profile())->extension_service();
75 DCHECK(extension_service);
76
77 const Extension* extension = extension_service->GetInstalledExtension(id());
78 if (extension) {
79 LaunchApp(extension);
80 return;
81 }
82
83 BeginInstall();
84 }
85
EphemeralAppLauncher(const std::string & webstore_item_id,Profile * profile,gfx::NativeWindow parent_window,const Callback & callback)86 EphemeralAppLauncher::EphemeralAppLauncher(
87 const std::string& webstore_item_id,
88 Profile* profile,
89 gfx::NativeWindow parent_window,
90 const Callback& callback)
91 : WebstoreStandaloneInstaller(
92 webstore_item_id,
93 profile,
94 callback),
95 parent_window_(parent_window),
96 dummy_web_contents_(
97 WebContents::Create(WebContents::CreateParams(profile))) {
98 Init();
99 }
100
EphemeralAppLauncher(const std::string & webstore_item_id,content::WebContents * web_contents,const Callback & callback)101 EphemeralAppLauncher::EphemeralAppLauncher(
102 const std::string& webstore_item_id,
103 content::WebContents* web_contents,
104 const Callback& callback)
105 : WebstoreStandaloneInstaller(
106 webstore_item_id,
107 ProfileForWebContents(web_contents),
108 callback),
109 content::WebContentsObserver(web_contents),
110 parent_window_(NativeWindowForWebContents(web_contents)) {
111 Init();
112 }
113
~EphemeralAppLauncher()114 EphemeralAppLauncher::~EphemeralAppLauncher() {}
115
Init()116 void EphemeralAppLauncher::Init() {
117 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
118 content::Source<Profile>(profile()->GetOriginalProfile()));
119 }
120
LaunchApp(const Extension * extension) const121 void EphemeralAppLauncher::LaunchApp(const Extension* extension) const {
122 DCHECK(extension);
123 if (!extension->is_app()) {
124 LOG(ERROR) << "Unable to launch extension " << extension->id()
125 << ". It is not an app.";
126 return;
127 }
128
129 AppLaunchParams params(profile(), extension, NEW_FOREGROUND_TAB);
130 params.desktop_type =
131 chrome::GetHostDesktopTypeForNativeWindow(parent_window_);
132 OpenApplication(params);
133 }
134
CheckRequestorAlive() const135 bool EphemeralAppLauncher::CheckRequestorAlive() const {
136 return dummy_web_contents_.get() != NULL || web_contents() != NULL;
137 }
138
GetRequestorURL() const139 const GURL& EphemeralAppLauncher::GetRequestorURL() const {
140 return GURL::EmptyGURL();
141 }
142
ShouldShowPostInstallUI() const143 bool EphemeralAppLauncher::ShouldShowPostInstallUI() const {
144 return false;
145 }
146
ShouldShowAppInstalledBubble() const147 bool EphemeralAppLauncher::ShouldShowAppInstalledBubble() const {
148 return false;
149 }
150
GetWebContents() const151 WebContents* EphemeralAppLauncher::GetWebContents() const {
152 return web_contents() ? web_contents() : dummy_web_contents_.get();
153 }
154
155 scoped_ptr<ExtensionInstallPrompt::Prompt>
CreateInstallPrompt() const156 EphemeralAppLauncher::CreateInstallPrompt() const {
157 return make_scoped_ptr(new ExtensionInstallPrompt::Prompt(
158 ExtensionInstallPrompt::LAUNCH_PROMPT));
159 }
160
CheckInlineInstallPermitted(const base::DictionaryValue & webstore_data,std::string * error) const161 bool EphemeralAppLauncher::CheckInlineInstallPermitted(
162 const base::DictionaryValue& webstore_data,
163 std::string* error) const {
164 *error = "";
165 return true;
166 }
167
CheckRequestorPermitted(const base::DictionaryValue & webstore_data,std::string * error) const168 bool EphemeralAppLauncher::CheckRequestorPermitted(
169 const base::DictionaryValue& webstore_data,
170 std::string* error) const {
171 *error = "";
172 return true;
173 }
174
CheckInstallValid(const base::DictionaryValue & manifest,std::string * error)175 bool EphemeralAppLauncher::CheckInstallValid(
176 const base::DictionaryValue& manifest,
177 std::string* error) {
178 extensions::Manifest extension_manifest(
179 extensions::Manifest::INTERNAL,
180 scoped_ptr<DictionaryValue>(manifest.DeepCopy()));
181 if (!extension_manifest.is_app()) {
182 *error = kExtensionTypeError;
183 return false;
184 }
185
186 return true;
187 }
188
189 scoped_ptr<ExtensionInstallPrompt>
CreateInstallUI()190 EphemeralAppLauncher::CreateInstallUI() {
191 if (web_contents())
192 return make_scoped_ptr(new ExtensionInstallPrompt(web_contents()));
193
194 return make_scoped_ptr(
195 new ExtensionInstallPrompt(profile(), parent_window_, NULL));
196 }
197
198 scoped_ptr<WebstoreInstaller::Approval>
CreateApproval() const199 EphemeralAppLauncher::CreateApproval() const {
200 scoped_ptr<WebstoreInstaller::Approval> approval =
201 WebstoreStandaloneInstaller::CreateApproval();
202 approval->is_ephemeral = true;
203 return approval.Pass();
204 }
205
CompleteInstall(const std::string & error)206 void EphemeralAppLauncher::CompleteInstall(const std::string& error) {
207 if (!error.empty())
208 WebstoreStandaloneInstaller::CompleteInstall(error);
209
210 // If the installation succeeds, we reach this point as a result of
211 // chrome::NOTIFICATION_EXTENSION_INSTALLED, but this is broadcasted before
212 // ExtensionService has added the extension to its list of installed
213 // extensions and is too early to launch the app. Instead, we will launch at
214 // chrome::NOTIFICATION_EXTENSION_LOADED.
215 // TODO(tmdiep): Refactor extensions/WebstoreInstaller or
216 // WebstoreStandaloneInstaller to support this cleanly.
217 }
218
WebContentsDestroyed(content::WebContents * web_contents)219 void EphemeralAppLauncher::WebContentsDestroyed(
220 content::WebContents* web_contents) {
221 AbortInstall();
222 }
223
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)224 void EphemeralAppLauncher::Observe(
225 int type,
226 const content::NotificationSource& source,
227 const content::NotificationDetails& details) {
228 switch (type) {
229 case chrome::NOTIFICATION_EXTENSION_LOADED: {
230 const extensions::Extension* extension =
231 content::Details<const extensions::Extension>(details).ptr();
232 DCHECK(extension);
233 if (extension->id() == id()) {
234 LaunchApp(extension);
235 WebstoreStandaloneInstaller::CompleteInstall(std::string());
236 }
237 break;
238 }
239
240 default:
241 NOTREACHED();
242 }
243 }
244